From 86419af414a055ee93ed0d2bfeb60a7a3301dcd0 Mon Sep 17 00:00:00 2001 From: Vishal Sharma Date: Fri, 10 Feb 2023 18:53:16 +0530 Subject: [PATCH] feat: add low_cardinal_exception_grouping config (#92) --- .../clickhouse_exporter.go | 25 +++++++++++++------ exporter/clickhousetracesexporter/config.go | 6 +++-- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/exporter/clickhousetracesexporter/clickhouse_exporter.go b/exporter/clickhousetracesexporter/clickhouse_exporter.go index f33e314d..784654bc 100644 --- a/exporter/clickhousetracesexporter/clickhouse_exporter.go +++ b/exporter/clickhousetracesexporter/clickhouse_exporter.go @@ -70,7 +70,7 @@ func newExporter(cfg component.ExporterConfig, logger *zap.Logger) (*storage, er return nil, err } - storage := storage{Writer: spanWriter, usageCollector: collector} + storage := storage{Writer: spanWriter, usageCollector: collector, config: storageConfig{lowCardinalExceptionGrouping: configClickHouse.LowCardinalExceptionGrouping}} return &storage, nil } @@ -78,6 +78,11 @@ func newExporter(cfg component.ExporterConfig, logger *zap.Logger) (*storage, er type storage struct { Writer Writer usageCollector *usage.UsageCollector + config storageConfig +} + +type storageConfig struct { + lowCardinalExceptionGrouping bool } func makeJaegerProtoReferences( @@ -212,7 +217,7 @@ func populateOtherDimensions(attributes pcommon.Map, span *Span) { } -func populateEvents(events ptrace.SpanEventSlice, span *Span) { +func populateEvents(events ptrace.SpanEventSlice, span *Span, lowCardinalExceptionGrouping bool) { for i := 0; i < events.Len(); i++ { event := Event{} event.Name = events.At(i).Name() @@ -229,8 +234,14 @@ func populateEvents(events ptrace.SpanEventSlice, span *Span) { uuidWithHyphen := uuid.New() uuid := strings.Replace(uuidWithHyphen.String(), "-", "", -1) span.ErrorID = uuid - hmd5 := md5.Sum([]byte(span.ServiceName + span.ErrorEvent.AttributeMap["exception.type"] + span.ErrorEvent.AttributeMap["exception.message"])) - span.ErrorGroupID = fmt.Sprintf("%x", hmd5) + var hash [16]byte + if lowCardinalExceptionGrouping { + hash = md5.Sum([]byte(span.ServiceName + span.ErrorEvent.AttributeMap["exception.type"])) + } else { + hash = md5.Sum([]byte(span.ServiceName + span.ErrorEvent.AttributeMap["exception.type"] + span.ErrorEvent.AttributeMap["exception.message"])) + + } + span.ErrorGroupID = fmt.Sprintf("%x", hash) } stringEvent, _ := json.Marshal(event) span.Events = append(span.Events, string(stringEvent)) @@ -242,7 +253,7 @@ func populateTraceModel(span *Span) { span.TraceModel.HasError = span.HasError } -func newStructuredSpan(otelSpan ptrace.Span, ServiceName string, resource pcommon.Resource) *Span { +func newStructuredSpan(otelSpan ptrace.Span, ServiceName string, resource pcommon.Resource, config storageConfig) *Span { durationNano := uint64(otelSpan.EndTimestamp() - otelSpan.StartTimestamp()) attributes := otelSpan.Attributes() @@ -323,7 +334,7 @@ func newStructuredSpan(otelSpan ptrace.Span, ServiceName string, resource pcommo span.HasError = true } populateOtherDimensions(attributes, span) - populateEvents(otelSpan.Events(), span) + populateEvents(otelSpan.Events(), span, config.lowCardinalExceptionGrouping) populateTraceModel(span) return span @@ -349,7 +360,7 @@ func (s *storage) pushTraceData(ctx context.Context, td ptrace.Traces) error { for k := 0; k < spans.Len(); k++ { span := spans.At(k) // traceID := hex.EncodeToString(span.TraceID()) - structuredSpan := newStructuredSpan(span, serviceName, rs.Resource()) + structuredSpan := newStructuredSpan(span, serviceName, rs.Resource(), s.config) err := s.Writer.WriteSpan(structuredSpan) if err != nil { zap.S().Error("Error in writing spans to clickhouse: ", err) diff --git a/exporter/clickhousetracesexporter/config.go b/exporter/clickhousetracesexporter/config.go index a704ab4d..39b3056e 100644 --- a/exporter/clickhousetracesexporter/config.go +++ b/exporter/clickhousetracesexporter/config.go @@ -19,7 +19,7 @@ import ( "go.opentelemetry.io/collector/config" ) -// Config defines configuration for logging exporter. +// Config defines configuration for tracing exporter. type Config struct { config.ExporterSettings `mapstructure:",squash"` // squash ensures fields are correctly decoded in embedded struct @@ -27,7 +27,9 @@ type Config struct { Datasource string `mapstructure:"datasource"` Migrations string `mapstructure:"migrations"` // Docker Multi Node Cluster is a flag to enable the docker multi node cluster. Default is false. - DockerMultiNodeCluster bool `mapstructure:"docker_multi_node_cluster" default:"false"` + DockerMultiNodeCluster bool `mapstructure:"docker_multi_node_cluster"` + // LowCardinalExceptionGrouping is a flag to enable exception grouping by serviceName + exceptionType. Default is false. + LowCardinalExceptionGrouping bool `mapstructure:"low_cardinal_exception_grouping"` } var _ component.ExporterConfig = (*Config)(nil)