Skip to content

Commit 5641945

Browse files
authored
[logzioexporter] Remove dependency on jaeger dbmodel (#36972)
<!--Ex. Fixing a bug - Describe the bug and how this fixes the issue. Ex. Adding a feature - Explain what this achieves.--> #### Description Copy the Jaeger plugin/storage/es/spanstore/dbmodel for logzioexporter, and remove the dependency. The dbmodel package in Jaeger will be internal from v1.65 (jaegertracing/jaeger#6428). <!-- Issue number (e.g. #36970) or full URL to issue, if applicable. --> #### Link to tracking issue Fixes #36970 <!--Describe what testing was performed and which tests were added.--> #### Testing Covered by existing <!--Describe the documentation added.--> <!--Please delete paragraphs that you did not use before submitting.-->
1 parent 11afd33 commit 5641945

File tree

8 files changed

+459
-39
lines changed

8 files changed

+459
-39
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: enhancement
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
7+
component: logzioexporter
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Remove jaeger dbmodel dependency.
11+
12+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
13+
issues: [36972]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext:
19+
20+
# If your change doesn't affect end users or the exported elements of any package,
21+
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
22+
# Optional: The change log or logs in which this entry should be included.
23+
# e.g. '[user]' or '[user, api]'
24+
# Include 'user' if the change is relevant to end users.
25+
# Include 'api' if there is a change to a library API.
26+
# Default: '[user]'
27+
change_logs: [user]
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
// Copyright The OpenTelemetry Authors
2+
// Copyright (c) 2019 The Jaeger Authors.
3+
// Copyright (c) 2018 Uber Technologies, Inc.
4+
// SPDX-License-Identifier: Apache-2.0
5+
6+
package logzioexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/logzioexporter"
7+
8+
import (
9+
"strings"
10+
11+
"github.com/jaegertracing/jaeger/model"
12+
13+
"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/logzioexporter/internal/dbmodel"
14+
)
15+
16+
// newFromDomain creates fromDomain used to convert model span to db span
17+
func newFromDomain(allTagsAsObject bool, tagKeysAsFields []string, tagDotReplacement string) fromDomain {
18+
tags := map[string]bool{}
19+
for _, k := range tagKeysAsFields {
20+
tags[k] = true
21+
}
22+
return fromDomain{allTagsAsFields: allTagsAsObject, tagKeysAsFields: tags, tagDotReplacement: tagDotReplacement}
23+
}
24+
25+
// fromDomain is used to convert model span to db span
26+
type fromDomain struct {
27+
allTagsAsFields bool
28+
tagKeysAsFields map[string]bool
29+
tagDotReplacement string
30+
}
31+
32+
// fromDomainEmbedProcess converts model.span into json.span format.
33+
// This format includes a ParentSpanID and an embedded process.
34+
func (fd fromDomain) fromDomainEmbedProcess(span *model.Span) *logzioSpan {
35+
return fd.convertSpanEmbedProcess(span)
36+
}
37+
38+
func (fd fromDomain) convertSpanInternal(span *model.Span) logzioSpan {
39+
tags, tagsMap := fd.convertKeyValuesString(span.Tags)
40+
return logzioSpan{
41+
TraceID: dbmodel.TraceID(span.TraceID.String()),
42+
SpanID: dbmodel.SpanID(span.SpanID.String()),
43+
Flags: uint32(span.Flags),
44+
OperationName: span.OperationName,
45+
StartTime: model.TimeAsEpochMicroseconds(span.StartTime),
46+
StartTimeMillis: model.TimeAsEpochMicroseconds(span.StartTime) / 1000,
47+
Duration: model.DurationAsMicroseconds(span.Duration),
48+
Tags: tags,
49+
Tag: tagsMap,
50+
Logs: fd.convertLogs(span.Logs),
51+
}
52+
}
53+
54+
func (fd fromDomain) convertSpanEmbedProcess(span *model.Span) *logzioSpan {
55+
s := fd.convertSpanInternal(span)
56+
s.Process = fd.convertProcess(span.Process)
57+
s.References = fd.convertReferences(span)
58+
return &s
59+
}
60+
61+
func (fd fromDomain) convertReferences(span *model.Span) []dbmodel.Reference {
62+
out := make([]dbmodel.Reference, 0, len(span.References))
63+
for _, ref := range span.References {
64+
out = append(out, dbmodel.Reference{
65+
RefType: fd.convertRefType(ref.RefType),
66+
TraceID: dbmodel.TraceID(ref.TraceID.String()),
67+
SpanID: dbmodel.SpanID(ref.SpanID.String()),
68+
})
69+
}
70+
return out
71+
}
72+
73+
func (fromDomain) convertRefType(refType model.SpanRefType) dbmodel.ReferenceType {
74+
if refType == model.FollowsFrom {
75+
return dbmodel.FollowsFrom
76+
}
77+
return dbmodel.ChildOf
78+
}
79+
80+
func (fd fromDomain) convertKeyValuesString(keyValues model.KeyValues) ([]dbmodel.KeyValue, map[string]any) {
81+
var tagsMap map[string]any
82+
var kvs []dbmodel.KeyValue
83+
for _, kv := range keyValues {
84+
if kv.GetVType() != model.BinaryType && (fd.allTagsAsFields || fd.tagKeysAsFields[kv.Key]) {
85+
if tagsMap == nil {
86+
tagsMap = map[string]any{}
87+
}
88+
tagsMap[strings.ReplaceAll(kv.Key, ".", fd.tagDotReplacement)] = kv.Value()
89+
} else {
90+
kvs = append(kvs, convertKeyValue(kv))
91+
}
92+
}
93+
if kvs == nil {
94+
kvs = make([]dbmodel.KeyValue, 0)
95+
}
96+
return kvs, tagsMap
97+
}
98+
99+
func (fromDomain) convertLogs(logs []model.Log) []dbmodel.Log {
100+
out := make([]dbmodel.Log, len(logs))
101+
for i, log := range logs {
102+
var kvs []dbmodel.KeyValue
103+
for _, kv := range log.Fields {
104+
kvs = append(kvs, convertKeyValue(kv))
105+
}
106+
out[i] = dbmodel.Log{
107+
Timestamp: model.TimeAsEpochMicroseconds(log.Timestamp),
108+
Fields: kvs,
109+
}
110+
}
111+
return out
112+
}
113+
114+
func (fd fromDomain) convertProcess(process *model.Process) dbmodel.Process {
115+
tags, tagsMap := fd.convertKeyValuesString(process.Tags)
116+
return dbmodel.Process{
117+
ServiceName: process.ServiceName,
118+
Tags: tags,
119+
Tag: tagsMap,
120+
}
121+
}
122+
123+
func convertKeyValue(kv model.KeyValue) dbmodel.KeyValue {
124+
return dbmodel.KeyValue{
125+
Key: kv.Key,
126+
Type: dbmodel.ValueType(strings.ToLower(kv.VType.String())),
127+
Value: kv.AsString(),
128+
}
129+
}
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
// Copyright The OpenTelemetry Authors
2+
// Copyright (c) 2019 The Jaeger Authors.
3+
// Copyright (c) 2018 Uber Technologies, Inc.
4+
// SPDX-License-Identifier: Apache-2.0
5+
6+
package logzioexporter
7+
8+
import (
9+
"bytes"
10+
"encoding/hex"
11+
"encoding/json"
12+
"fmt"
13+
"os"
14+
"testing"
15+
16+
"github.com/gogo/protobuf/jsonpb"
17+
"github.com/jaegertracing/jaeger/model"
18+
"github.com/stretchr/testify/assert"
19+
"github.com/stretchr/testify/require"
20+
21+
"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/logzioexporter/internal/dbmodel"
22+
)
23+
24+
func TestFromDomainEmbedProcess(t *testing.T) {
25+
domainStr, jsonStr := loadModel(t)
26+
27+
var span model.Span
28+
require.NoError(t, jsonpb.Unmarshal(bytes.NewReader(domainStr), &span))
29+
converter := newFromDomain(false, nil, ":")
30+
embeddedSpan := converter.fromDomainEmbedProcess(&span)
31+
32+
var expectedSpan logzioSpan
33+
require.NoError(t, json.Unmarshal(jsonStr, &expectedSpan))
34+
35+
testJSONEncoding(t, jsonStr, embeddedSpan)
36+
}
37+
38+
// Loads and returns domain model and JSON model.
39+
func loadModel(t *testing.T) ([]byte, []byte) {
40+
inStr, err := os.ReadFile("./testdata/span.json")
41+
require.NoError(t, err)
42+
outStr, err := os.ReadFile("./testdata/logziospan.json")
43+
require.NoError(t, err)
44+
return inStr, outStr
45+
}
46+
47+
func testJSONEncoding(t *testing.T, expectedStr []byte, object any) {
48+
buf := &bytes.Buffer{}
49+
enc := json.NewEncoder(buf)
50+
enc.SetIndent("", " ")
51+
require.NoError(t, enc.Encode(object))
52+
if !assert.Equal(t, string(expectedStr), buf.String()) {
53+
err := os.WriteFile("model-actual.json", buf.Bytes(), 0o600)
54+
require.NoError(t, err)
55+
}
56+
}
57+
58+
func TestEmptyTags(t *testing.T) {
59+
tags := make([]model.KeyValue, 0)
60+
span := model.Span{Tags: tags, Process: &model.Process{Tags: tags}}
61+
converter := newFromDomain(false, nil, ":")
62+
dbSpan := converter.fromDomainEmbedProcess(&span)
63+
assert.Empty(t, dbSpan.Tags)
64+
assert.Empty(t, dbSpan.Tag)
65+
}
66+
67+
func TestTagMap(t *testing.T) {
68+
tags := []model.KeyValue{
69+
model.String("foo", "foo"),
70+
model.Bool("a", true),
71+
model.Int64("b.b", 1),
72+
}
73+
span := model.Span{Tags: tags, Process: &model.Process{Tags: tags}}
74+
converter := newFromDomain(false, []string{"a", "b.b", "b*"}, ":")
75+
dbSpan := converter.fromDomainEmbedProcess(&span)
76+
77+
assert.Len(t, dbSpan.Tags, 1)
78+
assert.Equal(t, "foo", dbSpan.Tags[0].Key)
79+
assert.Len(t, dbSpan.Process.Tags, 1)
80+
assert.Equal(t, "foo", dbSpan.Process.Tags[0].Key)
81+
82+
tagsMap := map[string]any{}
83+
tagsMap["a"] = true
84+
tagsMap["b:b"] = int64(1)
85+
assert.Equal(t, tagsMap, dbSpan.Tag)
86+
assert.Equal(t, tagsMap, dbSpan.Process.Tag)
87+
}
88+
89+
func TestConvertKeyValueValue(t *testing.T) {
90+
longString := `Bender Bending Rodrigues Bender Bending Rodrigues Bender Bending Rodrigues Bender Bending Rodrigues
91+
Bender Bending Rodrigues Bender Bending Rodrigues Bender Bending Rodrigues Bender Bending Rodrigues Bender Bending Rodrigues
92+
Bender Bending Rodrigues Bender Bending Rodrigues Bender Bending Rodrigues Bender Bending Rodrigues Bender Bending Rodrigues
93+
Bender Bending Rodrigues Bender Bending Rodrigues Bender Bending Rodrigues Bender Bending Rodrigues Bender Bending Rodrigues
94+
Bender Bending Rodrigues Bender Bending Rodrigues Bender Bending Rodrigues Bender Bending Rodrigues Bender Bending Rodrigues `
95+
key := "key"
96+
tests := []struct {
97+
kv model.KeyValue
98+
expected dbmodel.KeyValue
99+
}{
100+
{
101+
kv: model.Bool(key, true),
102+
expected: dbmodel.KeyValue{Key: key, Value: "true", Type: "bool"},
103+
},
104+
{
105+
kv: model.Bool(key, false),
106+
expected: dbmodel.KeyValue{Key: key, Value: "false", Type: "bool"},
107+
},
108+
{
109+
kv: model.Int64(key, int64(1499)),
110+
expected: dbmodel.KeyValue{Key: key, Value: "1499", Type: "int64"},
111+
},
112+
{
113+
kv: model.Float64(key, float64(15.66)),
114+
expected: dbmodel.KeyValue{Key: key, Value: "15.66", Type: "float64"},
115+
},
116+
{
117+
kv: model.String(key, longString),
118+
expected: dbmodel.KeyValue{Key: key, Value: longString, Type: "string"},
119+
},
120+
{
121+
kv: model.Binary(key, []byte(longString)),
122+
expected: dbmodel.KeyValue{Key: key, Value: hex.EncodeToString([]byte(longString)), Type: "binary"},
123+
},
124+
{
125+
kv: model.KeyValue{VType: 1500, Key: key},
126+
expected: dbmodel.KeyValue{Key: key, Value: "unknown type 1500", Type: "1500"},
127+
},
128+
}
129+
130+
for _, test := range tests {
131+
t.Run(fmt.Sprintf("%s:%s", test.expected.Type, test.expected.Key), func(t *testing.T) {
132+
actual := convertKeyValue(test.kv)
133+
assert.Equal(t, test.expected, actual)
134+
})
135+
}
136+
}

exporter/logzioexporter/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ go 1.22.7
55
toolchain go1.22.8
66

77
require (
8+
github.com/gogo/protobuf v1.3.2
89
github.com/hashicorp/go-hclog v1.6.3
910
github.com/jaegertracing/jaeger v1.64.0
1011
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/jaeger v0.116.0
@@ -38,7 +39,6 @@ require (
3839
github.com/go-logr/logr v1.4.2 // indirect
3940
github.com/go-logr/stdr v1.2.2 // indirect
4041
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
41-
github.com/gogo/protobuf v1.3.2 // indirect
4242
github.com/golang/snappy v0.0.4 // indirect
4343
github.com/google/uuid v1.6.0 // indirect
4444
github.com/hashicorp/go-version v1.7.0 // indirect
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// Copyright The OpenTelemetry Authors
2+
// Copyright (c) 2019 The Jaeger Authors.
3+
// Copyright (c) 2018 Uber Technologies, Inc.
4+
// SPDX-License-Identifier: Apache-2.0
5+
6+
package dbmodel // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/logzioexporter/internal/dbmodel"
7+
8+
// ReferenceType is the reference type of one span to another
9+
type ReferenceType string
10+
11+
// TraceID is the shared trace ID of all spans in the trace.
12+
type TraceID string
13+
14+
// SpanID is the id of a span
15+
type SpanID string
16+
17+
// ValueType is the type of a value stored in KeyValue struct.
18+
type ValueType string
19+
20+
const (
21+
// ChildOf means a span is the child of another span
22+
ChildOf ReferenceType = "CHILD_OF"
23+
// FollowsFrom means a span follows from another span
24+
FollowsFrom ReferenceType = "FOLLOWS_FROM"
25+
26+
// StringType indicates a string value stored in KeyValue
27+
StringType ValueType = "string"
28+
// BoolType indicates a Boolean value stored in KeyValue
29+
BoolType ValueType = "bool"
30+
// Int64Type indicates a 64bit signed integer value stored in KeyValue
31+
Int64Type ValueType = "int64"
32+
// Float64Type indicates a 64bit float value stored in KeyValue
33+
Float64Type ValueType = "float64"
34+
// BinaryType indicates an arbitrary byte array stored in KeyValue
35+
BinaryType ValueType = "binary"
36+
)
37+
38+
// Reference is a reference from one span to another
39+
type Reference struct {
40+
RefType ReferenceType `json:"refType"`
41+
TraceID TraceID `json:"traceID"`
42+
SpanID SpanID `json:"spanID"`
43+
}
44+
45+
// Process is the process emitting a set of spans
46+
type Process struct {
47+
ServiceName string `json:"serviceName"`
48+
Tags []KeyValue `json:"tags"`
49+
// Alternative representation of tags for better kibana support
50+
Tag map[string]any `json:"tag,omitempty"`
51+
}
52+
53+
// Log is a log emitted in a span
54+
type Log struct {
55+
Timestamp uint64 `json:"timestamp"`
56+
Fields []KeyValue `json:"fields"`
57+
}
58+
59+
// KeyValue is a key-value pair with typed value.
60+
type KeyValue struct {
61+
Key string `json:"key"`
62+
Type ValueType `json:"type,omitempty"`
63+
Value any `json:"value"`
64+
}
65+
66+
// Service is the JSON struct for service:operation documents in ElasticSearch
67+
type Service struct {
68+
ServiceName string `json:"serviceName"`
69+
OperationName string `json:"operationName"`
70+
}

0 commit comments

Comments
 (0)