Skip to content

Commit 3cb736b

Browse files
authored
[connector/otlpjson] Add connector's implementations (#34249)
**Description:** <Describe what has changed.> <!--Ex. Fixing a bug - Describe the bug and how this fixes the issue. Ex. Adding a feature - Explain what this achieves.--> This is the 2nd PR for the new `otlpjson` connector (#34208). Adds the `ConsumeLogs` methods for the logs, metrics and traces respective connector types. At the moment, the connector retrieves the otlp json from the incoming Log's `Body`. This is not configurable yet. It can be decided if that needs to be. In addition, there is no attribute/metadata extraction/transfer from the incoming Log. This can be added in future iterations. **Link to tracking Issue:** <Issue number if applicable> #34208 #34239 **Testing:** <Describe what testing was performed and which tests were added.> Added. **Documentation:** <Describe the documentation added.> ~ Signed-off-by: ChrsMark <[email protected]>
1 parent 1c06ffb commit 3cb736b

File tree

6 files changed

+185
-3
lines changed

6 files changed

+185
-3
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: otlpjsonconnector
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Add connector's implementations
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: [34249, 34208]
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: []

connector/otlpjsonconnector/factory_test.go

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,18 @@ package otlpjsonconnector
66
import (
77
"context"
88
"testing"
9+
"time"
910

1011
"github.com/stretchr/testify/assert"
12+
"github.com/stretchr/testify/require"
13+
"go.opentelemetry.io/collector/component/componenttest"
1114
"go.opentelemetry.io/collector/connector/connectortest"
1215
"go.opentelemetry.io/collector/consumer"
16+
"go.opentelemetry.io/collector/consumer/consumertest"
1317
"go.opentelemetry.io/collector/pdata/plog"
18+
"go.opentelemetry.io/collector/pdata/pmetric"
19+
"go.opentelemetry.io/collector/pdata/ptrace"
20+
"go.opentelemetry.io/collector/pdata/testdata"
1421
)
1522

1623
func TestNewFactory(t *testing.T) {
@@ -28,3 +35,93 @@ func TestNewFactory(t *testing.T) {
2835
assert.NoError(t, err)
2936
assert.NotNil(t, conn)
3037
}
38+
39+
func TestLogsToLogs(t *testing.T) {
40+
factory := NewFactory()
41+
cfg := factory.CreateDefaultConfig().(*Config)
42+
43+
sink := &consumertest.LogsSink{}
44+
conn, err := factory.CreateLogsToLogs(context.Background(),
45+
connectortest.NewNopSettings(), cfg, sink)
46+
require.NoError(t, err)
47+
require.NotNil(t, conn)
48+
assert.False(t, conn.Capabilities().MutatesData)
49+
50+
require.NoError(t, conn.Start(context.Background(), componenttest.NewNopHost()))
51+
defer func() {
52+
assert.NoError(t, conn.Shutdown(context.Background()))
53+
}()
54+
55+
lp := testdata.GenerateLogs(1)
56+
marshaler := &plog.JSONMarshaler{}
57+
b, err := marshaler.MarshalLogs(lp)
58+
require.NoError(t, err)
59+
60+
testLogs := testdata.GenerateLogs(1)
61+
testLogs.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(0).Body().SetStr(string(b))
62+
assert.NoError(t, conn.ConsumeLogs(context.Background(), testLogs))
63+
64+
time.Sleep(1 * time.Second)
65+
require.Len(t, sink.AllLogs(), 1)
66+
assert.EqualValues(t, lp, sink.AllLogs()[0])
67+
}
68+
69+
func TestLogsToMetrics(t *testing.T) {
70+
factory := NewFactory()
71+
cfg := factory.CreateDefaultConfig().(*Config)
72+
73+
sink := &consumertest.MetricsSink{}
74+
conn, err := factory.CreateLogsToMetrics(context.Background(),
75+
connectortest.NewNopSettings(), cfg, sink)
76+
require.NoError(t, err)
77+
require.NotNil(t, conn)
78+
assert.False(t, conn.Capabilities().MutatesData)
79+
80+
require.NoError(t, conn.Start(context.Background(), componenttest.NewNopHost()))
81+
defer func() {
82+
assert.NoError(t, conn.Shutdown(context.Background()))
83+
}()
84+
85+
mt := testdata.GenerateMetrics(1)
86+
marshaler := &pmetric.JSONMarshaler{}
87+
b, err := marshaler.MarshalMetrics(mt)
88+
require.NoError(t, err)
89+
90+
testLogs := testdata.GenerateLogs(1)
91+
testLogs.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(0).Body().SetStr(string(b))
92+
assert.NoError(t, conn.ConsumeLogs(context.Background(), testLogs))
93+
94+
time.Sleep(1 * time.Second)
95+
require.Len(t, sink.AllMetrics(), 1)
96+
assert.EqualValues(t, mt, sink.AllMetrics()[0])
97+
}
98+
99+
func TestLogsToTraces(t *testing.T) {
100+
factory := NewFactory()
101+
cfg := factory.CreateDefaultConfig().(*Config)
102+
103+
sink := &consumertest.TracesSink{}
104+
conn, err := factory.CreateLogsToTraces(context.Background(),
105+
connectortest.NewNopSettings(), cfg, sink)
106+
require.NoError(t, err)
107+
require.NotNil(t, conn)
108+
assert.False(t, conn.Capabilities().MutatesData)
109+
110+
require.NoError(t, conn.Start(context.Background(), componenttest.NewNopHost()))
111+
defer func() {
112+
assert.NoError(t, conn.Shutdown(context.Background()))
113+
}()
114+
115+
td := testdata.GenerateTraces(1)
116+
marshaler := &ptrace.JSONMarshaler{}
117+
b, err := marshaler.MarshalTraces(td)
118+
require.NoError(t, err)
119+
120+
testLogs := testdata.GenerateLogs(1)
121+
testLogs.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(0).Body().SetStr(string(b))
122+
assert.NoError(t, conn.ConsumeLogs(context.Background(), testLogs))
123+
124+
time.Sleep(1 * time.Second)
125+
require.Len(t, sink.AllTraces(), 1)
126+
assert.EqualValues(t, td, sink.AllTraces()[0])
127+
}

connector/otlpjsonconnector/go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ require (
99
go.opentelemetry.io/collector/connector v0.105.1-0.20240717163034-43ed6184f9fe
1010
go.opentelemetry.io/collector/consumer v0.105.1-0.20240717163034-43ed6184f9fe
1111
go.opentelemetry.io/collector/pdata v1.12.1-0.20240716231837-5753a58f712b
12+
go.opentelemetry.io/collector/pdata/testdata v0.105.0
1213
go.uber.org/goleak v1.3.0
1314
go.uber.org/zap v1.27.0
1415
)
@@ -41,6 +42,7 @@ require (
4142
go.opentelemetry.io/collector/config/configtelemetry v0.105.1-0.20240717163034-43ed6184f9fe // indirect
4243
go.opentelemetry.io/collector/featuregate v1.12.1-0.20240716231837-5753a58f712b // indirect
4344
go.opentelemetry.io/collector/internal/globalgates v0.105.0 // indirect
45+
go.opentelemetry.io/collector/pdata/pprofile v0.105.0 // indirect
4446
go.opentelemetry.io/otel v1.28.0 // indirect
4547
go.opentelemetry.io/otel/exporters/prometheus v0.50.0 // indirect
4648
go.opentelemetry.io/otel/metric v1.28.0 // indirect

connector/otlpjsonconnector/logs.go

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,24 @@ func (c *connectorLogs) Capabilities() consumer.Capabilities {
4040
}
4141

4242
// ConsumeLogs method is called for each instance of a log sent to the connector
43-
func (c *connectorLogs) ConsumeLogs(_ context.Context, _ plog.Logs) error {
43+
func (c *connectorLogs) ConsumeLogs(ctx context.Context, pl plog.Logs) error {
44+
// loop through the levels of logs
45+
logsUnmarshaler := &plog.JSONUnmarshaler{}
46+
for i := 0; i < pl.ResourceLogs().Len(); i++ {
47+
li := pl.ResourceLogs().At(i)
48+
for j := 0; j < li.ScopeLogs().Len(); j++ {
49+
logRecord := li.ScopeLogs().At(j)
50+
for k := 0; k < logRecord.LogRecords().Len(); k++ {
51+
lRecord := logRecord.LogRecords().At(k)
52+
token := lRecord.Body()
53+
var l plog.Logs
54+
l, _ = logsUnmarshaler.UnmarshalLogs([]byte(token.AsString()))
55+
err := c.logsConsumer.ConsumeLogs(ctx, l)
56+
if err != nil {
57+
c.logger.Error("could not extract logs from otlp json", zap.Error(err))
58+
}
59+
}
60+
}
61+
}
4462
return nil
4563
}

connector/otlpjsonconnector/metrics.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"go.opentelemetry.io/collector/connector"
1111
"go.opentelemetry.io/collector/consumer"
1212
"go.opentelemetry.io/collector/pdata/plog"
13+
"go.opentelemetry.io/collector/pdata/pmetric"
1314
"go.uber.org/zap"
1415
)
1516

@@ -40,6 +41,24 @@ func (c *connectorMetrics) Capabilities() consumer.Capabilities {
4041
}
4142

4243
// ConsumeLogs method is called for each instance of a log sent to the connector
43-
func (c *connectorMetrics) ConsumeLogs(_ context.Context, _ plog.Logs) error {
44+
func (c *connectorMetrics) ConsumeLogs(ctx context.Context, pl plog.Logs) error {
45+
// loop through the levels of logs
46+
metricsUnmarshaler := &pmetric.JSONUnmarshaler{}
47+
for i := 0; i < pl.ResourceLogs().Len(); i++ {
48+
li := pl.ResourceLogs().At(i)
49+
for j := 0; j < li.ScopeLogs().Len(); j++ {
50+
logRecord := li.ScopeLogs().At(j)
51+
for k := 0; k < logRecord.LogRecords().Len(); k++ {
52+
lRecord := logRecord.LogRecords().At(k)
53+
token := lRecord.Body()
54+
var m pmetric.Metrics
55+
m, _ = metricsUnmarshaler.UnmarshalMetrics([]byte(token.AsString()))
56+
err := c.metricsConsumer.ConsumeMetrics(ctx, m)
57+
if err != nil {
58+
c.logger.Error("could not extract metrics from otlp json", zap.Error(err))
59+
}
60+
}
61+
}
62+
}
4463
return nil
4564
}

connector/otlpjsonconnector/traces.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"go.opentelemetry.io/collector/connector"
1111
"go.opentelemetry.io/collector/consumer"
1212
"go.opentelemetry.io/collector/pdata/plog"
13+
"go.opentelemetry.io/collector/pdata/ptrace"
1314
"go.uber.org/zap"
1415
)
1516

@@ -40,6 +41,24 @@ func (c *connectorTraces) Capabilities() consumer.Capabilities {
4041
}
4142

4243
// ConsumeLogs method is called for each instance of a log sent to the connector
43-
func (c *connectorTraces) ConsumeLogs(_ context.Context, _ plog.Logs) error {
44+
func (c *connectorTraces) ConsumeLogs(ctx context.Context, pl plog.Logs) error {
45+
// loop through the levels of logs
46+
tracesUnmarshaler := &ptrace.JSONUnmarshaler{}
47+
for i := 0; i < pl.ResourceLogs().Len(); i++ {
48+
li := pl.ResourceLogs().At(i)
49+
for j := 0; j < li.ScopeLogs().Len(); j++ {
50+
logRecord := li.ScopeLogs().At(j)
51+
for k := 0; k < logRecord.LogRecords().Len(); k++ {
52+
lRecord := logRecord.LogRecords().At(k)
53+
token := lRecord.Body()
54+
var t ptrace.Traces
55+
t, _ = tracesUnmarshaler.UnmarshalTraces([]byte(token.AsString()))
56+
err := c.tracesConsumer.ConsumeTraces(ctx, t)
57+
if err != nil {
58+
c.logger.Error("could not extract traces from otlp json", zap.Error(err))
59+
}
60+
}
61+
}
62+
}
4463
return nil
4564
}

0 commit comments

Comments
 (0)