@@ -6,15 +6,28 @@ package telemetry // import "go.opentelemetry.io/collector/service/telemetry"
6
6
import (
7
7
"context"
8
8
"errors"
9
+ "io"
10
+ "net/http"
11
+ "net/http/httptest"
9
12
"reflect"
10
13
"testing"
11
14
"time"
12
15
16
+ "github.com/stretchr/testify/assert"
13
17
"github.com/stretchr/testify/require"
14
18
config "go.opentelemetry.io/contrib/otelconf/v0.3.0"
19
+ "go.uber.org/zap"
15
20
"go.uber.org/zap/zapcore"
21
+ "go.uber.org/zap/zaptest/observer"
22
+
23
+ "go.opentelemetry.io/collector/pdata/plog/plogotlp"
24
+ semconv "go.opentelemetry.io/collector/semconv/v1.18.0"
16
25
)
17
26
27
+ type shutdownable interface {
28
+ Shutdown (context.Context ) error
29
+ }
30
+
18
31
func TestNewLogger (t * testing.T ) {
19
32
tests := []struct {
20
33
name string
@@ -102,9 +115,6 @@ func TestNewLogger(t *testing.T) {
102
115
require .NoError (t , err )
103
116
gotType := reflect .TypeOf (l .Core ()).String ()
104
117
require .Equal (t , wantCoreType , gotType )
105
- type shutdownable interface {
106
- Shutdown (context.Context ) error
107
- }
108
118
if prov , ok := lp .(shutdownable ); ok {
109
119
require .NoError (t , prov .Shutdown (context .Background ()))
110
120
}
@@ -114,3 +124,149 @@ func TestNewLogger(t *testing.T) {
114
124
testCoreType (t , tt .wantCoreType )
115
125
}
116
126
}
127
+
128
+ func TestNewLoggerWithResource (t * testing.T ) {
129
+ observerCore , observedLogs := observer .New (zap .InfoLevel )
130
+
131
+ set := Settings {
132
+ ZapOptions : []zap.Option {
133
+ zap .WrapCore (func (core zapcore.Core ) zapcore.Core {
134
+ // Combine original core and observer core to capture everything
135
+ return zapcore .NewTee (core , observerCore )
136
+ }),
137
+ },
138
+ }
139
+
140
+ cfg := Config {
141
+ Logs : LogsConfig {
142
+ Level : zapcore .InfoLevel ,
143
+ Encoding : "json" ,
144
+ },
145
+ Resource : map [string ]* string {
146
+ "myfield" : ptr ("myvalue" ),
147
+ },
148
+ }
149
+
150
+ mylogger , _ , _ := newLogger (set , cfg )
151
+
152
+ mylogger .Info ("Test log message" )
153
+ require .Len (t , observedLogs .All (), 1 )
154
+
155
+ entry := observedLogs .All ()[0 ]
156
+ assert .Equal (t , "resource" , entry .Context [0 ].Key )
157
+ dict := entry .Context [0 ].Interface .(zapcore.ObjectMarshaler )
158
+ enc := zapcore .NewMapObjectEncoder ()
159
+ require .NoError (t , dict .MarshalLogObject (enc ))
160
+ require .Equal (t , "myvalue" , enc .Fields ["myfield" ])
161
+ }
162
+
163
+ func TestOTLPLogExport (t * testing.T ) {
164
+ version := "1.2.3"
165
+ service := "test-service"
166
+ testAttribute := "test-attribute"
167
+ testValue := "test-value"
168
+ receivedLogs := 0
169
+ totalLogs := 10
170
+
171
+ // Create a backend to receive the logs and assert the content
172
+ srv := createBackend ("/v1/logs" , func (writer http.ResponseWriter , request * http.Request ) {
173
+ body , err := io .ReadAll (request .Body )
174
+ assert .NoError (t , err )
175
+ defer request .Body .Close ()
176
+
177
+ // Unmarshal the protobuf body into logs
178
+ req := plogotlp .NewExportRequest ()
179
+ err = req .UnmarshalProto (body )
180
+ assert .NoError (t , err )
181
+
182
+ logs := req .Logs ()
183
+ rl := logs .ResourceLogs ().At (0 )
184
+
185
+ resourceAttrs := rl .Resource ().Attributes ().AsRaw ()
186
+ assert .Equal (t , resourceAttrs [semconv .AttributeServiceName ], service )
187
+ assert .Equal (t , resourceAttrs [semconv .AttributeServiceVersion ], version )
188
+ assert .Equal (t , resourceAttrs [testAttribute ], testValue )
189
+
190
+ // Check that the resource attributes are not duplicated in the log records
191
+ sl := rl .ScopeLogs ().At (0 )
192
+ logRecord := sl .LogRecords ().At (0 )
193
+ attrs := logRecord .Attributes ().AsRaw ()
194
+ assert .NotContains (t , attrs , semconv .AttributeServiceName )
195
+ assert .NotContains (t , attrs , semconv .AttributeServiceVersion )
196
+ assert .NotContains (t , attrs , testAttribute )
197
+
198
+ receivedLogs ++
199
+
200
+ writer .WriteHeader (http .StatusOK )
201
+ })
202
+ defer srv .Close ()
203
+
204
+ processors := []config.LogRecordProcessor {
205
+ {
206
+ Simple : & config.SimpleLogRecordProcessor {
207
+ Exporter : config.LogRecordExporter {
208
+ OTLP : & config.OTLP {
209
+ Endpoint : ptr (srv .URL ),
210
+ Protocol : ptr ("http/protobuf" ),
211
+ Insecure : ptr (true ),
212
+ },
213
+ },
214
+ },
215
+ },
216
+ }
217
+
218
+ cfg := Config {
219
+ Logs : LogsConfig {
220
+ Level : zapcore .DebugLevel ,
221
+ Development : true ,
222
+ Encoding : "json" ,
223
+ Processors : processors ,
224
+ },
225
+ }
226
+
227
+ sdk , _ := config .NewSDK (
228
+ config .WithOpenTelemetryConfiguration (
229
+ config.OpenTelemetryConfiguration {
230
+ LoggerProvider : & config.LoggerProvider {
231
+ Processors : processors ,
232
+ },
233
+ Resource : & config.Resource {
234
+ SchemaUrl : ptr ("" ),
235
+ Attributes : []config.AttributeNameValue {
236
+ {Name : semconv .AttributeServiceName , Value : service },
237
+ {Name : semconv .AttributeServiceVersion , Value : version },
238
+ {Name : testAttribute , Value : testValue },
239
+ },
240
+ },
241
+ },
242
+ ),
243
+ )
244
+
245
+ l , lp , err := newLogger (Settings {SDK : & sdk }, cfg )
246
+ require .NoError (t , err )
247
+ require .NotNil (t , l )
248
+ require .NotNil (t , lp )
249
+
250
+ defer func () {
251
+ if prov , ok := lp .(shutdownable ); ok {
252
+ require .NoError (t , prov .Shutdown (context .Background ()))
253
+ }
254
+ }()
255
+
256
+ // Reset counter for each test case
257
+ receivedLogs = 0
258
+
259
+ // Generate some logs to send to the backend
260
+ for i := 0 ; i < totalLogs ; i ++ {
261
+ l .Info ("Test log message" )
262
+ }
263
+
264
+ // Ensure the correct number of logs were received
265
+ require .Equal (t , totalLogs , receivedLogs )
266
+ }
267
+
268
+ func createBackend (endpoint string , handler func (writer http.ResponseWriter , request * http.Request )) * httptest.Server {
269
+ mux := http .NewServeMux ()
270
+ mux .HandleFunc (endpoint , handler )
271
+ return httptest .NewServer (mux )
272
+ }
0 commit comments