mirror of
https://github.com/hanzoai/otel-collector.git
synced 2026-10-30 18:26:25 +00:00
Modules declare go 1.27.1 and the build images follow. go fix applied the modernizers; omitzero is not applied, since it changes what the JSON says. Co-authored-by: Hanzo Dev <[email protected]>
170 lines
4.3 KiB
Go
170 lines
4.3 KiB
Go
package grok
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/hanzoai/otel-collector/pkg/grok"
|
|
o11ylogspipelinestanzaoperator "github.com/hanzoai/otel-collector/processor/o11ylogspipelineprocessor/stanza/operator"
|
|
o11ystanzahelper "github.com/hanzoai/otel-collector/processor/o11ylogspipelineprocessor/stanza/operator/helper"
|
|
"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/entry"
|
|
"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/operator"
|
|
"go.opentelemetry.io/collector/component"
|
|
)
|
|
|
|
const operatorType = "grok_parser"
|
|
|
|
func init() {
|
|
operator.Register(operatorType, func() operator.Builder { return NewConfig() })
|
|
o11ylogspipelinestanzaoperator.Register(operatorType, func() operator.Builder { return NewConfig() })
|
|
}
|
|
|
|
// NewConfig creates a new grok parser config with default values
|
|
func NewConfig() *Config {
|
|
return NewConfigWithID(operatorType)
|
|
}
|
|
|
|
// NewConfigWithID creates a new grok parser config with default values
|
|
func NewConfigWithID(operatorID string) *Config {
|
|
return &Config{
|
|
ParserConfig: o11ystanzahelper.NewParserConfig(operatorID, operatorType),
|
|
}
|
|
}
|
|
|
|
// Config is the configuration of a grok parser operator.
|
|
type Config struct {
|
|
o11ystanzahelper.ParserConfig `mapstructure:",squash"`
|
|
|
|
// grok pattern
|
|
Pattern string `mapstructure:"pattern"`
|
|
|
|
Cache struct {
|
|
Size uint16 `mapstructure:"size"`
|
|
} `mapstructure:"cache"`
|
|
|
|
// array of keys that will be present in the final values
|
|
Include []string `mapstructure:"include"`
|
|
|
|
// array of keys that will be removed from the final values
|
|
Exclude []string `mapstructure:"exclude"`
|
|
}
|
|
|
|
// Build will build a grok parser operator.
|
|
func (c Config) Build(set component.TelemetrySettings) (operator.Operator, error) {
|
|
parserOperator, err := c.ParserConfig.Build(set)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if c.Pattern == "" {
|
|
return nil, fmt.Errorf("missing required field 'pattern'")
|
|
}
|
|
|
|
g, err := grok.NewWithConfig(&grok.Config{NamedCapturesOnly: true})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("new grok object: %w", err)
|
|
}
|
|
|
|
include := make(map[string]struct{})
|
|
exclude := make(map[string]struct{})
|
|
includeKeysPresent := false
|
|
excludeKeysPresent := false
|
|
if len(c.Include) > 0 {
|
|
includeKeysPresent = true
|
|
for _, k := range c.Include {
|
|
include[k] = struct{}{}
|
|
}
|
|
}
|
|
if len(c.Exclude) > 0 {
|
|
excludeKeysPresent = true
|
|
for _, k := range c.Exclude {
|
|
exclude[k] = struct{}{}
|
|
}
|
|
}
|
|
|
|
op := &Parser{
|
|
ParserOperator: parserOperator,
|
|
grok: g,
|
|
pattern: c.Pattern,
|
|
includeKeysPresent: includeKeysPresent,
|
|
include: include,
|
|
excludeKeysPresent: excludeKeysPresent,
|
|
exclude: exclude,
|
|
}
|
|
|
|
if c.Cache.Size > 0 {
|
|
op.cache = newMemoryCache(c.Cache.Size, 0)
|
|
set.Logger.Sugar().Debugf("configured %s with memory cache of size %d", op.ID(), op.cache.maxSize())
|
|
}
|
|
|
|
return op, nil
|
|
}
|
|
|
|
// Parser is an operator that parses grok in an entry.
|
|
type Parser struct {
|
|
o11ystanzahelper.ParserOperator
|
|
grok *grok.Grok
|
|
pattern string
|
|
cache cache
|
|
includeKeysPresent bool
|
|
include map[string]struct{}
|
|
excludeKeysPresent bool
|
|
exclude map[string]struct{}
|
|
}
|
|
|
|
// Process will parse an entry for grok.
|
|
func (r *Parser) Process(ctx context.Context, entry *entry.Entry) error {
|
|
return r.ParserOperator.ProcessWith(ctx, entry, r.parse)
|
|
}
|
|
|
|
func (r *Parser) ProcessBatch(ctx context.Context, entries []*entry.Entry) error {
|
|
return r.ProcessBatchWith(ctx, entries, r.Process)
|
|
}
|
|
|
|
// parse will parse a value using the supplied grok.
|
|
func (r *Parser) parse(value any) (any, error) {
|
|
var raw string
|
|
switch m := value.(type) {
|
|
case string:
|
|
raw = m
|
|
default:
|
|
return nil, fmt.Errorf("type '%T' cannot be parsed as grok", value)
|
|
}
|
|
return r.match(raw)
|
|
}
|
|
|
|
func (r *Parser) match(value string) (any, error) {
|
|
if r.cache != nil {
|
|
if x := r.cache.get(value); x != nil {
|
|
return x, nil
|
|
}
|
|
}
|
|
|
|
values, err := r.grok.ParseTyped(r.pattern, value)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to parse log: %v", err.Error())
|
|
}
|
|
|
|
parsedValues := map[string]any{}
|
|
for k, v := range values {
|
|
if r.excludeKeysPresent {
|
|
if _, ok := r.exclude[k]; ok {
|
|
continue
|
|
}
|
|
}
|
|
if r.includeKeysPresent {
|
|
if _, ok := r.include[k]; ok {
|
|
parsedValues[k] = v
|
|
}
|
|
} else {
|
|
parsedValues[k] = v
|
|
}
|
|
}
|
|
|
|
if r.cache != nil {
|
|
r.cache.add(value, parsedValues)
|
|
}
|
|
|
|
return parsedValues, nil
|
|
}
|