Skip to main content

Command Palette

Search for a command to run...

OTel Collector - Filter Processor 的用法很多種?

Updated
13 min read
OTel Collector - Filter Processor 的用法很多種?

Filter Processor 常見設定方式

心血來潮打開 TG,看到有大大在詢問關於 OpenTelemetry Collector (contrib) 的 Filter processor 的使用方法。 第一個問題是關於 Metrics,為什麼官方網站上看到的是 metrics

processors:
    # Data sources: metrics
    filter:
        metrics:
            include:
            match_type: regexp
            metric_names:
                - prefix/.*
                - prefix_.*

而套件網站寫的是 metrics.metric

processors:
    filter:
        metrics:
            metric:
                - 'name == "my.metric" and resource.attributes["my_label"] == "abc123"'
                - 'type == METRIC_DATA_TYPE_HISTOGRAM'
            datapoint:
                - 'metric.type == METRIC_DATA_TYPE_SUMMARY'
                - 'resource.attributes["service.name"] == "my_service_name"'

第二個問題是關於 Span,一樣官方網站看到的是 trace.span

processors:
  filter/ottl:
    error_mode: ignore
    traces:
      span:
        - |
        resource.attributes["service.name"] != "app1" and
        resource.attributes["service.name"] != "app2" and
        resource.attributes["service.name"] != "app3"

對岸的部落格寫的則是 spans

processors:
  filter/allowlist: # 保留滿足條件的 span
    spans:
      include:
        match_type: strict
        services:
          - app1
          - app2
          - app3

問題是什麼樣的寫法是最正確、齊全的用法。

結論是,全部都是正確的寫法!

如果只是要使用正則表達式來查詢metric name欄位且為模糊的範圍或該欄位有多種值,查詢會如下。 關於match_type,在使用正則表達式需要使用match_type: regexp,而如果該欄位的值要正確比對只是有多種值得可能則match_type: strict。 又如果是使用內建的 Filter Metric Label 表達式的話,則是使用match_type: expr。如HasLabelLabel

filter/regexp:
    metrics:
        include:
        match_type: regexp
        metric_names: [prefix/.*, .*contains.*, .*_suffix, full_name_match]
filter/regexpincludeoptions:
    metrics: 
        include:
        match_type: regexp
        metric_names:
            - prefix/.*
            - prefix_.*
            - .*contains.*
            - .*_suffix
filter/regexpexcludeoptions:
    metrics: 
        exclude:
            match_type: regex
            metric_names:
                - hello/.*
filter/includestrict:
  metrics:
    include:
      match_type: strict
      metric_names:
        - hello_world
        - hello/world
filter/exprinclude:
  metrics:
    include:
      match_type: expr
      expressions:
        - Label("foo") == "bar"
        - HasLabel("baz")

filter/strict:
    spans:
        include:
            match_type: strict
            services:
            - app1
            - app2
            - app3
            attributes:
            - key: should_include
                value: "(true|probably_true)"

但若是要對多個欄位或做更為複雜的查詢操作時會使用到 OTTL ,則會如下 在 Yaml 的表達上就會不同了。且不能正則表達式的比對方法與 OTTL 比對方法同時存在於同一個filter中(cannot use ottl conditions and include/exclude for metrics at the same time),原因文章後面會提及。

filter/ottldrop:
    error_mode: ignore
    metrics:
      metric:
        - type == METRIC_DATA_TYPE_NONE
    traces:
      span:
        - IsMatch(resource.attributes["k8s.pod.name"], "local")

filter/ottlmetricstraces:
metrics:
    metric: # 針對 HISTOGRAM 類型的資料,name 和 resource.attributes["my_label"] 滿足條件的就過濾
        - 'name == "my.metric" and resource.attributes["my_label"] == "abc123"'
        - 'type == METRIC_DATA_TYPE_HISTOGRAM'
    datapoint: # 針對 datapoint 做過濾,但只針對 metric.type 是 SUMMARY 類型的資料
        - 'metric.type == METRIC_DATA_TYPE_SUMMARY'
traces:
      span: # 針對 Span
        - 'attributes["container.name"] == "app_container_1"'
        - 'resource.attributes["host.name"] == "localhost"'
        - 'name == "app_3"'
      spanevent: # 針對 Span Event
        - 'attributes["grpc"] == true'
        - 'IsMatch(name, ".*grpc.*")'

多種混用就要命名多個filter,反正流水線執行順序是依照在各類型遙測資料流水線中安排的順序。記得軟體設計的原則,單一職責的概念,每一個 Filter 盡量只處理單一欄位或比對或單一需求所需的最基本處理。組合排序的部份流給 pipeline。

filter/metrics_mix_config:
  metrics:
    include:
      match_type: expr
      expressions:
        - Label("foo") == "bar"
        - HasLabel("baz")

filter/ottlmetricname:
  metric:
    - 'attributes["test"] == "pass"'

filter/spans_mix_config:
  spans:
    include:
      match_type: strict
      services:
        - test
        - test2
      attributes:
        - key: should_include
          value: "(true|probably_true)"
  traces:
    span:
      - 'attributes["test"] == "pass"'

關於 OTTL 常見語法

  • Paths
  • Lists
  • Literals
  • Enums
  • Converters
  • Math expression

關於 OTTL 常見函數

  • append
  • delete
  • keep
  • flatten
  • limit
  • merge_maps
  • replace
  • set
  • truncate

Filter Processor 程式碼解析

設定檔解析

先針對config.go擷取部份定義。 設定檔中對應的就是 Config,有5種成員屬性,error_modemetricslogsspanstraces

// Config defines configuration for Resource processor.
type Config struct {
    // ErrorMode determines how the processor reacts to errors that occur while processing an OTTL condition.
    // Valid values are `ignore` and `propagate`.
    // `ignore` means the processor ignores errors returned by conditions and continues on to the next condition. This is the recommended mode.
    // `propagate` means the processor returns the error up the pipeline.  This will result in the payload being dropped from the collector.
    // The default value is `propagate`.
    ErrorMode ottl.ErrorMode `mapstructure:"error_mode"`

    Metrics MetricFilters `mapstructure:"metrics"`

    Logs LogFilters `mapstructure:"logs"`

    Spans filterconfig.MatchConfig `mapstructure:"spans"`

    Traces TraceFilters `mapstructure:"traces"`
}

Metrics Matcher

接著是關於 metrics 區塊中的設定元素。 對應元素有 includeexcluderegexpmetricdatapoint

// MetricFilters filters by Metric properties.
type MetricFilters struct {
    // Include match properties describe metrics that should be included in the Collector Service pipeline,
    // all other metrics should be dropped from further processing.
    // If both Include and Exclude are specified, Include filtering occurs first.
    Include *filterconfig.MetricMatchProperties `mapstructure:"include"`

    // Exclude match properties describe metrics that should be excluded from the Collector Service pipeline,
    // all other metrics should be included.
    // If both Include and Exclude are specified, Include filtering occurs first.
    Exclude *filterconfig.MetricMatchProperties `mapstructure:"exclude"`

    // RegexpConfig specifies options for the regexp match type
    RegexpConfig *regexp.Config `mapstructure:"regexp"`

    // MetricConditions is a list of OTTL conditions for an ottlmetric context.
    // If any condition resolves to true, the metric will be dropped.
    // Supports `and`, `or`, and `()`
    MetricConditions []string `mapstructure:"metric"`

    // DataPointConditions is a list of OTTL conditions for an ottldatapoint context.
    // If any condition resolves to true, the datapoint will be dropped.
    // Supports `and`, `or`, and `()`
    DataPointConditions []string `mapstructure:"datapoint"`
}

接著是關於 span 區塊的設定元素。 對應元素有 includeexclude

// MatchConfig has two optional MatchProperties one to define what is processed
// by the processor, captured under the 'include' and the second, exclude, to
// define what is excluded from the processor.
type MatchConfig struct {
    // Include specifies the set of input data properties that must be present in order
    // for this processor to apply to it.
    // Note: If `exclude` is specified, the input data is compared against those
    // properties after the `include` properties.
    // This is an optional field. If neither `include` and `exclude` are set, all input data
    // are processed. If `include` is set and `exclude` isn't set, then all
    // input data matching the properties in this structure are processed.
    Include *MatchProperties `mapstructure:"include"`

    // Exclude specifies when this processor will not be applied to the input data
    // which match the specified properties.
    // Note: The `exclude` properties are checked after the `include` properties,
    // if they exist, are checked.
    // If `include` isn't specified, the `exclude` properties are checked against
    // all input data.
    // This is an optional field. If neither `include` and `exclude` are set, all input data
    // is processed. If `exclude` is set and `include` isn't set, then all the
    // input data that does not match the properties in this structure are processed.
    Exclude *MatchProperties `mapstructure:"exclude"`
}

最後是關於 trace 區塊的設定元素。 對應元素有 spanspanevent

// TraceFilters filters by OTTL conditions
type TraceFilters struct {
    // SpanConditions is a list of OTTL conditions for an ottlspan context.
    // If any condition resolves to true, the span will be dropped.
    // Supports `and`, `or`, and `()`
    SpanConditions []string `mapstructure:"span"`

    // SpanEventConditions is a list of OTTL conditions for an ottlspanevent context.
    // If any condition resolves to true, the span event will be dropped.
    // Supports `and`, `or`, and `()`
    SpanEventConditions []string `mapstructure:"spanevent"`
}

其中 metrics 算是比較複雜的。

Metrics Filter 程式碼解析

MetricFilters

type MetricFilters struct {
    Include              *filterconfig.MetricMatchProperties `mapstructure:"include"`
    Exclude              *filterconfig.MetricMatchProperties `mapstructure:"exclude"`
    RegexpConfig         *regexp.Config                      `mapstructure:"regexp"`
    MetricConditions     []string                            `mapstructure:"metric"`
    DataPointConditions  []string                            `mapstructure:"datapoint"`
}
  • Include: 包含匹配屬性,描述應包含在流水線中的 metric。 如果指定了 Include 和 Exclude,會首先進行 Include 過濾。
  • Exclude: 排除匹配屬性,描述應從流水線中排除的 metric。 如果指定了 Include 和 Exclude,會首先進行 Include 過濾。
  • RegexpConfig: 指定正則表達式匹配類型的配置選項。
  • MetricConditions: 一組 OTTL 條件,針對 ottlmetric 上下文。如果任何條件為真,則該 metric 將被丟棄。 支援 andor 和括號 ()
  • DataPointConditions: 一組 OTTL 條件,針對 ottldatapoint 上下文。如果任何條件為真,則該 datapoint 將被丟棄。 支援 andor 和括號 ()

MetricMatchProperties

type MetricMatchProperties struct {
    MatchType           MetricMatchType `mapstructure:"match_type"`
    RegexpConfig        *regexp.Config  `mapstructure:"regexp"`
    MetricNames         []string        `mapstructure:"metric_names"`
    Expressions         []string        `mapstructure:"expressions"`
    ResourceAttributes  []Attribute     `mapstructure:"resource_attributes"`
}

type MetricMatchType string

// These are the MetricMatchType that users can specify for filtering
// `pmetric.Metric`s.
const (
    MetricRegexp = MetricMatchType(filterset.Regexp)
    MetricStrict = MetricMatchType(filterset.Strict)
    MetricExpr   = "expr"
)
  • MatchType: 指定所需的匹配類型(例如 strict 或 regexp)。
  • RegexpConfig: 指定 MetricRegexp 匹配類型的配置選項。
  • MetricNames: 指定用於匹配 metric 名稱的字串模式列表。如果 metric 名稱匹配此列表中的至少一個字串模式,則匹配成功。
  • Expressions: 指定用於匹配 metric 的表達式列表。如果 metric 中的任何 datapoint 匹配此列表中的至少一個表達式,則匹配成功。
  • ResourceAttributes: 定義用於匹配 metric 的可能資源屬性列表。如果任何資源屬性匹配此列表中的所有表達式,則匹配成功。

上面的設定配置,被轉成 MetricMatchProperties 後呢就會被載入到 filter processor 的流水線中。

// fsp : filterMetricProcessor
fsp.skipMetricExpr, err = filtermetric.NewSkipExpr(cfg.Metrics.Include, cfg.Metrics.Exclude)
    if err != nil {
        return nil, err
    }

然後在 NewSkipExpr 建構式中會看到以下程式碼。會看到是先把 include 加到 matchers 再來才是添加 exclude。所以上述才會說先進行 include 過濾才進行 exclude。

// NewSkipExpr creates a BoolExpr that on evaluation returns true if a metric should NOT be processed or kept.
// The logic determining if a metric should be processed is based on include and exclude settings.
// Include properties are checked before exclude settings are checked.
func NewSkipExpr(include *filterconfig.MetricMatchProperties, exclude *filterconfig.MetricMatchProperties) (expr.BoolExpr[ottlmetric.TransformContext], error) {
    if UseOTTLBridge.IsEnabled() {
        return filterottl.NewMetricSkipExprBridge(include, exclude)
    }
    var matchers []expr.BoolExpr[ottlmetric.TransformContext]
    inclExpr, err := newExpr(include)
    if err != nil {
        return nil, err
    }
    if inclExpr != nil {
        matchers = append(matchers, expr.Not(inclExpr))
    }
    exclExpr, err := newExpr(exclude)
    if err != nil {
        return nil, err
    }
    if exclExpr != nil {
        matchers = append(matchers, exclExpr)
    }
    return expr.Or(matchers...), nil
}

// NewMatcher constructs a metric Matcher. If an 'expr' match type is specified,
// returns an expr matcher, otherwise a name matcher.
func newExpr(mp *filterconfig.MetricMatchProperties) (expr.BoolExpr[ottlmetric.TransformContext], error) {
    if mp == nil {
        return nil, nil
    }
    // 這裡就是 match_type: expr
    if mp.MatchType == filterconfig.MetricExpr {
        if len(mp.Expressions) == 0 {
            return nil, nil
        }
        return newExprMatcher(mp.Expressions)
    }
    if len(mp.MetricNames) == 0 {
        return nil, nil
    }
    return newNameMatcher(mp)
}

最後 match_type: regexp 的會返回 nameMatcher 類型的matcher。

// nameMatcher matches metrics by metric properties against prespecified values for each property.
type nameMatcher struct {
    // 儲存和處理metric名稱的過濾器集合
    nameFilters filterset.FilterSet
}

func newNameMatcher(mp *filterconfig.MetricMatchProperties) (*nameMatcher, error) {
    nameFS, err := filterset.CreateFilterSet(
        mp.MetricNames,
        &filterset.Config{
            MatchType:    filterset.MatchType(mp.MatchType), // 精確匹配或正則表達式匹配
            RegexpConfig: mp.RegexpConfig, // 正則表達式
        },
    )
    if err != nil {
        return nil, err
    }
    return &nameMatcher{nameFilters: nameFS}, nil
}

// Eval matches a metric using the metric properties configured on the nameMatcher.
// A metric only matches if every metric property configured on the nameMatcher is a match.
func (m *nameMatcher) Eval(_ context.Context, tCtx ottlmetric.TransformContext) (bool, error) {
    // 從上下文中獲取 metric 的名稱來進行比對
    return m.nameFilters.Matches(tCtx.GetMetric().Name()), nil
}

然後上述的都會轉成 expr.BoolExpr 的形式,這說明這比對只會回傳(bool, error),且這比對函數稱為 Eval

// BoolExpr is an interface that allows matching a context K against a configuration of a match.
type BoolExpr[K any] interface {
    Eval(ctx context.Context, tCtx K) (bool, error)
}

最後在執行處理 metric 的主要流程, 會在 ScopeMetrics 區段判斷是不是要對該筆資料 skip。

// processMetrics filters the given metrics based off the filterMetricProcessor's filters.
func (fmp *filterMetricProcessor) processMetrics(ctx context.Context, md pmetric.Metrics) (pmetric.Metrics, error) {
    if fmp.skipResourceExpr == nil && fmp.skipMetricExpr == nil && fmp.skipDataPointExpr == nil {
        return md, nil
    }

    ...
    var errors error
    md.ResourceMetrics().RemoveIf(func(rmetrics pmetric.ResourceMetrics) bool {
        ...
        rmetrics.ScopeMetrics().RemoveIf(func(smetrics pmetric.ScopeMetrics) bool {
            scope := smetrics.Scope()
            smetrics.Metrics().RemoveIf(func(metric pmetric.Metric) bool {
                if fmp.skipMetricExpr != nil {
                    skip, err := fmp.skipMetricExpr.Eval(ctx, ottlmetric.NewTransformContext(metric, smetrics.Metrics(), scope, resource, smetrics, rmetrics))
                    if err != nil {
                        errors = multierr.Append(errors, err)
                    }
                    if skip {
                        return true
                    }
                }
                ...
            })
            return smetrics.Metrics().Len() == 0
        })
        return rmetrics.ScopeMetrics().Len() == 0
    })

    ...
    return md, nil
}

Config

type Config struct {
    CacheEnabled       bool `mapstructure:"cacheenabled"`
    CacheMaxNumEntries int  `mapstructure:"cachemaxnumentries"`
}
  • CacheEnabled: 確定是否啟用 LRU 快取以加快後續的匹配速度。如果設置為 true,將啟用快取。
  • CacheMaxNumEntries: LRU 快取中存儲匹配結果的最大資料數量。如果 CacheEnabled 為 false,此設置將被忽略。

到這裡我們應該知道 metrics 中的 include 與 exclude 比對的對象就是 metric_name 以及 resource 中的 attributes,此處大同小異就不重複說明。 regexp 中的 cache 設定是能用很少的記憶體空間,暫存過往結果來加速比對。

接著來看看 metricdatapoint

metric 與 datapoint

當設定配置被載入到 filter processor,轉成對應類型的物件後,會呼叫func (cfg *Config) Validate()檢查設定配置是否正確。 會看到一句錯誤標語cannot use ottl conditions and include/exclude for metrics at the same time;我們不能把 include/exclude 與 OTTL 條件式放在同一個 filter 物件中。所以我們往後看,它這段也只會檢查 OTTL 的文法配置。也呼應最早提到不能正則表達式的比對方法與 OTTL 比對方法同時存在於同一個filter中(cannot use ottl conditions and include/exclude for metrics at the same time)

// Validate checks if the processor configuration is valid
func (cfg *Config) Validate() error {
    ...
    if (cfg.Metrics.MetricConditions != nil || cfg.Metrics.DataPointConditions != nil) && (cfg.Metrics.Include != nil || cfg.Metrics.Exclude != nil) {
        return fmt.Errorf("cannot use ottl conditions and include/exclude for metrics at the same time")
    }
    ...

    var errors error

    ...

    if cfg.Metrics.MetricConditions != nil {
        _, err := filterottl.NewBoolExprForMetric(cfg.Metrics.MetricConditions, filterottl.StandardMetricFuncs(), ottl.PropagateError, component.TelemetrySettings{Logger: zap.NewNop()})
        errors = multierr.Append(errors, err)
    }

    if cfg.Metrics.DataPointConditions != nil {
        _, err := filterottl.NewBoolExprForDataPoint(cfg.Metrics.DataPointConditions, filterottl.StandardDataPointFuncs(), ottl.PropagateError, component.TelemetrySettings{Logger: zap.NewNop()})
        errors = multierr.Append(errors, err)
    }

    ...

    return errors
}

再次來看到 filterMetricProcessor 的建構式。能發現這裡與正則表達式用的newSkipResExpr不同了。分別是用filterottl.NewBoolExprForMetricfilterottl.NewBoolExprForDataPoint

if cfg.Metrics.MetricConditions != nil || cfg.Metrics.DataPointConditions != nil {
        if cfg.Metrics.MetricConditions != nil {
            fsp.skipMetricExpr, err = filterottl.NewBoolExprForMetric(cfg.Metrics.MetricConditions, filterottl.StandardMetricFuncs(), cfg.ErrorMode, set.TelemetrySettings)
            if err != nil {
                return nil, err
            }
        }

        if cfg.Metrics.DataPointConditions != nil {
            fsp.skipDataPointExpr, err = filterottl.NewBoolExprForDataPoint(cfg.Metrics.DataPointConditions, filterottl.StandardDataPointFuncs(), cfg.ErrorMode, set.TelemetrySettings)
            if err != nil {
                return nil, err
            }
        }

        return fsp, nil
    }

NewBoolExprForMetric 與 NewBoolExprForDataPoint 這裡就不深入解釋了。反正就是回傳能按照表達式順序依序去執行擷取、轉換、或比對等操作的 OTTL 表達式。 回傳的也是 BoolExpr 跳到上述的 boolExpr

// NewBoolExprForMetric creates a BoolExpr[ottlmetric.TransformContext] that will return true if any of the given OTTL conditions evaluate to true.
// The passed in functions should use the ottlmetric.TransformContext.
// If a function named `match` is not present in the function map it will be added automatically so that parsing works as expected
func NewBoolExprForMetric(conditions []string, functions map[string]ottl.Factory[ottlmetric.TransformContext], errorMode ottl.ErrorMode, set component.TelemetrySettings) (expr.BoolExpr[ottlmetric.TransformContext], error) {
    parser, err := ottlmetric.NewParser(functions, set)
    if err != nil {
        return nil, err
    }
    statements, err := parser.ParseConditions(conditions)
    if err != nil {
        return nil, err
    }
    c := ottlmetric.NewConditionSequence(statements, set, ottlmetric.WithConditionSequenceErrorMode(errorMode))
    return &c, nil
}

// NewBoolExprForDataPoint creates a BoolExpr[ottldatapoint.TransformContext] that will return true if any of the given OTTL conditions evaluate to true.
// The passed in functions should use the ottldatapoint.TransformContext.
// If a function named `match` is not present in the function map it will be added automatically so that parsing works as expected
func NewBoolExprForDataPoint(conditions []string, functions map[string]ottl.Factory[ottldatapoint.TransformContext], errorMode ottl.ErrorMode, set component.TelemetrySettings) (expr.BoolExpr[ottldatapoint.TransformContext], error) {
    parser, err := ottldatapoint.NewParser(functions, set)
    if err != nil {
        return nil, err
    }
    statements, err := parser.ParseConditions(conditions)
    if err != nil {
        return nil, err
    }
    c := ottldatapoint.NewConditionSequence(statements, set, ottldatapoint.WithConditionSequenceErrorMode(errorMode))
    return &c, nil
}

首先我們要知道 metrics data 到底有哪些屬性。 參考自 metrics.proto

// MetricsData
// └─── ResourceMetrics
//   ├── Resource
//   ├── SchemaURL
//   └── ScopeMetrics
//      ├── Scope
//      ├── SchemaURL
//      └── Metric
//         ├── Name
//         ├── Description
//         ├── Unit
//         └── data
//            ├── Gauge
//            ├── Sum
//            ├── Histogram
//            ├── ExponentialHistogram
//            └── Summary

這裡看到的 在 Metric 以下的都是 metric 的範疇。這裡每種 type 裡面的具體監測數值或是 bucket data point 才是屬於 Data point。 像這裡都是 OTTL metric 能處理的屬性。最常見的就是 type 也就是上面的 Gauge、Sum、Histogram 等,還有 name 這些。 而 OTTL DataPoint 就不會看到 type 與 name 這種,而是各種 Metric point 內有的數值。有關於 Metric Point 能參考書中的 Ch 5-31 檢測點的說明

舉個例子︰

filter/ottlmetricname:
  metrics:
    metric:
      - 'name == "pass"'

filter/ottldatapoint:
  metrics:
    datapoint:
      - 'attributes["test"] == "pass"'
      - 'metric.name == "http_client_duration_bucket" and resource.attributes["service.name"] == "notification-sender"'
      - 'start_time_unix_nano < 1720881125000000000'

閱讀至此,什麼時候該用 regexp 什麼時候該用 OTTL 來比對 metrics 資料應該有了基本的認知了。

Trace Matcher 與 Spans Matcher

用來建立 traces 區塊的是 TraceFilters。

// TraceFilters filters by OTTL conditions
type TraceFilters struct {
    // SpanConditions is a list of OTTL conditions for an ottlspan context.
    // If any condition resolves to true, the span will be dropped.
    // Supports `and`, `or`, and `()`
    SpanConditions []string `mapstructure:"span"`

    // SpanEventConditions is a list of OTTL conditions for an ottlspanevent context.
    // If any condition resolves to true, the span event will be dropped.
    // Supports `and`, `or`, and `()`
    SpanEventConditions []string `mapstructure:"spanevent"`
}

而 Spans Matcher 則是 filterconfig.MatchConfig。從這組結構我們也能看出與上述的 metric MetricMatchProperties雷同。

// MatchConfig has two optional MatchProperties one to define what is processed
// by the processor, captured under the 'include' and the second, exclude, to
// define what is excluded from the processor.
type MatchConfig struct {
    Include *MatchProperties `mapstructure:"include"`

    Exclude *MatchProperties `mapstructure:"exclude"`
}

// MatchProperties specifies the set of properties in a spans/log/metric to match
// against and if the input data should be included or excluded from the
// processor. At least one of services (spans only), names or
// attributes must be specified. It is supported to have all specified, but
// this requires all the properties to match for the inclusion/exclusion to
// occur.
// The following are examples of invalid configurations:
//
//    attributes/bad1:
//      # This is invalid because include is specified with neither services or
//      # attributes.
//      include:
//      actions: ...
//
//    span/bad2:
//      exclude:
//          # This is invalid because services, span_names and attributes have empty values.
//        services:
//        span_names:
//        attributes:
//      actions: ...
//
// Please refer to processor/attributesprocessor/testdata/config.yaml and
// processor/spanprocessor/testdata/config.yaml for valid configurations.
type MatchProperties struct {
    Services []string `mapstructure:"services"`

    SpanNames []string `mapstructure:"span_names"`

    LogBodies []string `mapstructure:"log_bodies"`

    LogSeverityTexts []string `mapstructure:"log_severity_texts"`

    LogSeverityNumber *LogSeverityNumberMatchProperties `mapstructure:"log_severity_number"`

    MetricNames []string `mapstructure:"metric_names"`

    Attributes []Attribute `mapstructure:"attributes"`

    Resources []Attribute `mapstructure:"resources"`

    Libraries []InstrumentationLibrary `mapstructure:"libraries"`

    SpanKinds []string `mapstructure:"span_kinds"`
}

能參考書中的 Ch5-62 Trace Span 與 Span context 的關係圖。 Spans Matcher 只能比對關係圖中的 Span 上的屬性,幾乎就是針對名稱或 Kind 或是特定的 trace/span id 做比對。而 Trace Matcher 則能比對到下一層的 Span Event 的內容。

OTTL Span Context

OTTL Span Event Context

舉個例子︰


filter/spans:
  spans:
    include:
      match_type: strict
      services:
        - test
        - test2
      attributes:
        - key: should_include
          value: "(true|probably_true)"
    exclude:
      match_type: regexp
      attributes:
        - key: should_exclude
          value: "(probably_false|false)"

filter/ottl:
  error_mode: ignore
  traces:
    span:
      - 'attributes["test"] == "pass"'
    spanevent:
      - 'attributes["test"] == "pass"'

filter/ottlmultiline:
  traces:
    span:
      - 'attributes["test"] == "pass"'
      - 'attributes["test"] == "also pass"'

官網有提供一個易懂的 Span 資料,能讓我們清楚的知道 Span context 與 Span event 的內容。 Span Event 是我們開發者用於紀錄 Span 執行過程中有意義的事件(可能就是業務用,可能是 debug 用)。能參考書中的 Ch5-54 Events 的說明。

{
  "name": "hello-greetings",
  "context": {
    "trace_id": "0x5b8aa5a2d2c872e8321cf37308d69df2",
    "span_id": "0x5fb397be34d26b51"
  },
  "parent_id": "0x051581bf3cb55c13",
  "start_time": "2022-04-29T18:52:58.114304Z",
  "end_time": "2022-04-29T22:52:58.114561Z",
  "attributes": {
    "http.route": "some_route2"
  },
  "events": [
    {
      "name": "hey there!",
      "timestamp": "2022-04-29T18:52:58.114561Z",
      "attributes": {
        "event_attributes": 1
      }
    },
    {
      "name": "bye now!",
      "timestamp": "2022-04-29T18:52:58.114585Z",
      "attributes": {
        "event_attributes": 1
      }
    }
  ]
}

小結

由於 Filter Processor 與 Attribute Processor 會大量運用到 OTTL 以及正則表達式。但 OTTL 目前還沒到正式釋出 Stable 版本的程度。所以蠻多時候要自行解讀程式碼以及測試案例來理解怎使用。搭配書上的結構關係圖會更好理解。

原文來自OpenTelemetry 入門指南︰建立全面可觀測性架構

More from this blog

Claude Code 監控秘錄:OpenTelemetry(OTel/OTLP)實戰指南

稟告主公:此乃司馬懿進呈之兵書,詳解如何以 OpenTelemetry 陣法,令臥龍神算之一舉一動盡在掌握,知糧草消耗、察兵器效能、辨戰報異常,使主公運籌帷幄於大帳之中。 為何需要斥候情報? 司馬懿稟告主公: 臥龍神算(Claude Code)乃當世利器,然若無斥候回報,主公便如蒙眼行軍——兵器耗損幾何、糧草消費幾許、哪路斥候出了差錯,一概不知。臣以為,此乃兵家大忌。 無情報之弊,有四: 軍

Feb 19, 202610 min read164
Claude Code 監控秘錄:OpenTelemetry(OTel/OTLP)實戰指南

工程師的 Claude Code 實戰指南:從零開始到高效開發

工程師的 Claude Code 實戰指南:從零開始到高效開發 本文整合 Anthropic 官方 Best Practices 與社群實戰 Tips,帶你由淺入深掌握 Claude Code。 什麼是 Claude Code?為什麼值得學? 如果你還在用「複製程式碼貼到 ChatGPT,再複製答案貼回去」的工作流程,Claude Code 會讓你大開眼界。 Claude Code 是 Anthropic 推出的命令列工具,它直接活在你的 terminal 裡,能夠讀懂你的整個 codeb...

Feb 18, 20265 min read75
工程師的 Claude Code 實戰指南:從零開始到高效開發

System Design Interview Ch 12 Digital Wallet

確立問題與設計範疇 角色對話內容 面試者我們應該只關注兩個數位錢包之間的餘額轉帳操作嗎?我們是否需要擔心其他功能? 面試官讓我們只關注餘額轉帳操作。 面試者該系統需要支援多少 TPS(每秒交易次數)? 面試官讓我們假設是 1,000,000 TPS (每秒 100 萬次交易)。 面試者數位錢包對正確性有嚴格的要求。我們可以假設事務保證 就足夠了嗎? 面試官聽起來不錯。 面試者我們需要證明正確性嗎? 面試官這是一個很好的問題。正確性(Correctness)通常只有在交...

Feb 2, 202610 min read190
System Design Interview Ch 12 Digital Wallet

Claude Code 利用 Event-Driven Hooks 打造自動化開發大腦

在現代 AI 輔助開發中,我們不僅需要 AI 寫程式,更需要它懂規則、記性好,並且能自動處理那些繁瑣的雜事。透過 Claude Code Hooks 機制,我們可以介入 AI 的思考與執行迴圈,實現真正的「人機協作自動化」。 一、 動機與痛點:為什麼你需要介入 AI 的生命週期? 在預設狀態下,Claude Code 雖然強大,但它是「被動」且「無狀態」的,這導致了開發者常遇到以下痛點: 記憶重置 (Session Amnesia): 痛點:每次重啟終端機,AI 就像失憶一樣。 解法:你...

Jan 24, 20266 min read461
Claude Code 利用 Event-Driven Hooks 打造自動化開發大腦
M

MicroFIRE

71 posts