github.com/alibaba/ilogtail/pkg@v0.0.0-20250526110833-c53b480d046c/protocol/converter/otlp_test.go (about) 1 package protocol 2 3 import ( 4 "strconv" 5 "testing" 6 7 "github.com/smartystreets/goconvey/convey" 8 "go.opentelemetry.io/collector/pdata/plog" 9 10 "github.com/alibaba/ilogtail/pkg/config" 11 "github.com/alibaba/ilogtail/pkg/models" 12 "github.com/alibaba/ilogtail/pkg/protocol" 13 "github.com/alibaba/ilogtail/pkg/protocol/otlp" 14 15 systime "time" 16 ) 17 18 func TestNewConvertToOtlpLogs(t *testing.T) { 19 convey.Convey("When constructing converter with unsupported encoding", t, func() { 20 _, err := NewConverter(ProtocolOtlpV1, EncodingJSON, nil, nil, &config.GlobalConfig{}) 21 convey.So(err, convey.ShouldNotBeNil) 22 }) 23 24 convey.Convey("When constructing converter with supported encoding", t, func() { 25 c, err := NewConverter(ProtocolOtlpV1, EncodingNone, nil, nil, &config.GlobalConfig{}) 26 convey.So(err, convey.ShouldBeNil) 27 28 convey.Convey("When the logGroup is generated from files", func() { 29 time := []uint32{1662434209, 1662434487} 30 method := []string{"PUT", "GET"} 31 status := []string{"200", "404"} 32 logs := make([]*protocol.Log, 2) 33 for i := 0; i < 2; i++ { 34 logs[i] = &protocol.Log{ 35 Time: time[i], 36 Contents: []*protocol.Log_Content{ 37 {Key: "method", Value: method[i]}, 38 {Key: "status", Value: status[i]}, 39 {Key: "__tag__:__path__", Value: "/root/test/origin/example.log"}, 40 {Key: "__log_topic__", Value: "file"}, 41 {Key: "content", Value: "test log content"}, 42 }, 43 } 44 } 45 tags := []*protocol.LogTag{ 46 {Key: "__hostname__", Value: "alje834hgf"}, 47 {Key: "__pack_id__", Value: "AEDCFGHNJUIOPLMN-1E"}, 48 } 49 logGroup := &protocol.LogGroup{ 50 Logs: logs, 51 Category: "test", 52 Topic: "file", 53 Source: "172.10.0.56", 54 LogTags: tags, 55 MachineUUID: "machine_id", 56 } 57 d, err := c.Do(logGroup) 58 convey.Convey("Then the converted log should be valid", func() { 59 convey.So(err, convey.ShouldBeNil) 60 resourceLogs, ok := d.(plog.ResourceLogs) 61 convey.So(ok, convey.ShouldBeTrue) 62 convey.So(1, convey.ShouldEqual, resourceLogs.ScopeLogs().Len()) 63 convey.So(5, convey.ShouldEqual, resourceLogs.Resource().Attributes().Len()) 64 65 convey.Convey("Then the LogRecords should be valid", func() { 66 for i := 0; i < resourceLogs.ScopeLogs().Len(); i++ { 67 scope := resourceLogs.ScopeLogs().At(i) 68 convey.So(2, convey.ShouldEqual, scope.LogRecords().Len()) 69 70 for j := 0; j < scope.LogRecords().Len(); j++ { 71 logRecord := scope.LogRecords().At(j) 72 convey.So(logs[i].Contents[4].Value, convey.ShouldEqual, logRecord.Body().AsString()) 73 74 // Convert timestamp to unix seconds and compare with the original time 75 unixTimeSec := logRecord.Timestamp().AsTime().Unix() 76 convey.So(uint64(logs[j].Time), convey.ShouldEqual, unixTimeSec) 77 } 78 } 79 }) 80 }) 81 }) 82 }) 83 84 convey.Convey("When constructing converter with supported encoding", t, func() { 85 c, err := NewConverter(ProtocolOtlpV1, EncodingNone, nil, nil, &config.GlobalConfig{EnableTimestampNanosecond: true}) 86 convey.So(err, convey.ShouldBeNil) 87 88 convey.Convey("When the logGroup is generated from files", func() { 89 time := []uint32{1662434209, 1662434487} 90 namosec := systime.Now().Nanosecond() 91 timeNs := []uint32{uint32(namosec), uint32(namosec + 10)} 92 method := []string{"PUT", "GET"} 93 status := []string{"200", "404"} 94 logs := make([]*protocol.Log, 2) 95 for i := 0; i < 2; i++ { 96 logs[i] = &protocol.Log{ 97 Time: time[i], 98 Contents: []*protocol.Log_Content{ 99 {Key: "method", Value: method[i]}, 100 {Key: "status", Value: status[i]}, 101 {Key: "__tag__:__path__", Value: "/root/test/origin/example.log"}, 102 {Key: "__log_topic__", Value: "file"}, 103 {Key: "content", Value: "test log content"}, 104 }, 105 TimeNs: &timeNs[i], 106 } 107 } 108 tags := []*protocol.LogTag{ 109 {Key: "__hostname__", Value: "alje834hgf"}, 110 {Key: "__pack_id__", Value: "AEDCFGHNJUIOPLMN-1E"}, 111 } 112 logGroup := &protocol.LogGroup{ 113 Logs: logs, 114 Category: "test", 115 Topic: "file", 116 Source: "172.10.0.56", 117 LogTags: tags, 118 MachineUUID: "machine_id", 119 } 120 d, err := c.Do(logGroup) 121 convey.Convey("Then the converted log should be valid", func() { 122 convey.So(err, convey.ShouldBeNil) 123 resourceLogs, ok := d.(plog.ResourceLogs) 124 convey.So(ok, convey.ShouldBeTrue) 125 convey.So(1, convey.ShouldEqual, resourceLogs.ScopeLogs().Len()) 126 convey.So(5, convey.ShouldEqual, resourceLogs.Resource().Attributes().Len()) 127 128 convey.Convey("Then the LogRecords should be valid", func() { 129 for i := 0; i < resourceLogs.ScopeLogs().Len(); i++ { 130 scope := resourceLogs.ScopeLogs().At(i) 131 convey.So(2, convey.ShouldEqual, scope.LogRecords().Len()) 132 133 for j := 0; j < scope.LogRecords().Len(); j++ { 134 logRecord := scope.LogRecords().At(j) 135 convey.So(logs[i].Contents[4].Value, convey.ShouldEqual, logRecord.Body().AsString()) 136 137 // Convert timestamp to unix nanoseconds and compare with the original timeNs 138 unixTimeNano := logRecord.Timestamp().AsTime().UnixNano() 139 convey.So(uint64(logs[j].Time)*uint64(systime.Second)+uint64(*logs[j].TimeNs), convey.ShouldEqual, unixTimeNano) 140 } 141 } 142 }) 143 }) 144 }) 145 }) 146 } 147 148 func TestConvertPipelineGroupEventsToOtlpLogs(t *testing.T) { 149 convey.Convey("When constructing converter with supported encoding", t, func() { 150 c, err := NewConverter(ProtocolOtlpV1, EncodingNone, nil, nil, &config.GlobalConfig{}) 151 convey.So(err, convey.ShouldBeNil) 152 153 convey.Convey("When the logGroup is generated from files", func() { 154 time := []uint32{1662434209, 1662434487} 155 method := []string{"PUT", "GET"} 156 status := []string{"200", "404"} 157 pipelineGroupEvent := &models.PipelineGroupEvents{ 158 Group: &models.GroupInfo{ 159 Metadata: models.NewMetadata(), 160 Tags: models.NewTags(), 161 }, 162 } 163 164 pipelineGroupEvent.Group.Metadata.Add("__hostname__", "alje834hgf") 165 pipelineGroupEvent.Group.Metadata.Add("__pack_id__", "AEDCFGHNJUIOPLMN-1E") 166 for i := 0; i < 2; i++ { 167 tags := models.NewTagsWithMap( 168 map[string]string{ 169 "method": method[i], 170 "status": status[i], 171 "__tag__:__path__": "/root/test/origin/example.log", 172 "__log_topic__": "file", 173 "content": "test log content", 174 }, 175 ) 176 177 event := models.NewLog( 178 "log_name_"+strconv.Itoa(i), 179 []byte("message"), 180 "INFO", 181 "", 182 "", 183 tags, 184 uint64(time[i]), 185 ) 186 event.ObservedTimestamp = uint64(time[i] + 100) 187 pipelineGroupEvent.Events = append(pipelineGroupEvent.Events, event) 188 } 189 190 logs, metrics, traces, err := c.ConvertPipelineGroupEventsToOTLPEventsV1(pipelineGroupEvent) 191 convey.Convey("Then the converted logs should be valid", func() { 192 convey.So(err, convey.ShouldBeNil) 193 convey.So(1, convey.ShouldEqual, logs.ScopeLogs().Len()) 194 convey.So(2, convey.ShouldEqual, logs.Resource().Attributes().Len()) 195 convey.So(0, convey.ShouldEqual, metrics.ScopeMetrics().Len()) 196 convey.So(0, convey.ShouldEqual, traces.ScopeSpans().Len()) 197 198 convey.Convey("Then the logs should be valid", func() { 199 for i := 0; i < logs.ScopeLogs().Len(); i++ { 200 scope := logs.ScopeLogs().At(i) 201 convey.So(2, convey.ShouldEqual, scope.LogRecords().Len()) 202 203 for j := 0; j < scope.LogRecords().Len(); j++ { 204 log := scope.LogRecords().At(j) 205 event := pipelineGroupEvent.Events[j].(*models.Log) 206 convey.So(event.GetTimestamp(), convey.ShouldEqual, uint64(log.Timestamp())) 207 convey.So(event.GetObservedTimestamp(), convey.ShouldEqual, uint64(log.ObservedTimestamp())) 208 convey.So(event.GetBody(), convey.ShouldResemble, log.Body().Bytes().AsRaw()) 209 210 for k, v := range pipelineGroupEvent.Events[j].GetTags().Iterator() { 211 otTagValue, ok := log.Attributes().Get(k) 212 convey.So(ok, convey.ShouldBeTrue) 213 convey.So(v, convey.ShouldEqual, otTagValue.AsString()) 214 } 215 216 } 217 } 218 }) 219 }) 220 }) 221 }) 222 } 223 224 func TestConvertPipelineGroupEventsToOtlpMetrics(t *testing.T) { 225 convey.Convey("When constructing converter with supported encoding", t, func() { 226 c, err := NewConverter(ProtocolOtlpV1, EncodingNone, nil, nil, &config.GlobalConfig{}) 227 convey.So(err, convey.ShouldBeNil) 228 229 convey.Convey("When the logGroup is generated from files", func() { 230 time := []uint32{1662434209, 1662434487} 231 method := []string{"PUT", "GET"} 232 status := []string{"200", "404"} 233 pipelineGroupEvent := &models.PipelineGroupEvents{ 234 Group: &models.GroupInfo{ 235 Metadata: models.NewMetadata(), 236 Tags: models.NewTags(), 237 }, 238 } 239 240 pipelineGroupEvent.Group.Metadata.Add("__hostname__", "alje834hgf") 241 pipelineGroupEvent.Group.Metadata.Add("__pack_id__", "AEDCFGHNJUIOPLMN-1E") 242 for i := 0; i < 2; i++ { 243 tags := models.NewTagsWithMap( 244 map[string]string{ 245 "method": method[i], 246 "status": status[i], 247 "__tag__:__path__": "/root/test/origin/example.log", 248 "__log_topic__": "file", 249 "content": "test log content", 250 }, 251 ) 252 253 event := models.NewSingleValueMetric( 254 "metric_name_"+strconv.Itoa(i), 255 models.MetricTypeCounter, 256 tags, 257 int64(time[i]), 258 i+1, 259 ) 260 pipelineGroupEvent.Events = append(pipelineGroupEvent.Events, event) 261 } 262 263 logs, metrics, traces, err := c.ConvertPipelineGroupEventsToOTLPEventsV1(pipelineGroupEvent) 264 convey.Convey("Then the converted metrics should be valid", func() { 265 convey.So(err, convey.ShouldBeNil) 266 convey.So(0, convey.ShouldEqual, logs.ScopeLogs().Len()) 267 convey.So(0, convey.ShouldEqual, traces.ScopeSpans().Len()) 268 convey.So(1, convey.ShouldEqual, metrics.ScopeMetrics().Len()) 269 convey.So(2, convey.ShouldEqual, metrics.Resource().Attributes().Len()) 270 271 convey.Convey("Then the metrics should be valid", func() { 272 for i := 0; i < metrics.ScopeMetrics().Len(); i++ { 273 scope := metrics.ScopeMetrics().At(i) 274 convey.So(2, convey.ShouldEqual, scope.Metrics().Len()) 275 for j := 0; j < scope.Metrics().Len(); j++ { 276 metric := scope.Metrics().At(j) 277 convey.So("metric_name_"+strconv.Itoa(j), convey.ShouldEqual, metric.Name()) 278 metricSum := metric.Sum() 279 convey.So(1, convey.ShouldEqual, metricSum.DataPoints().Len()) 280 281 convey.So(pipelineGroupEvent.Events[j].GetTimestamp(), convey.ShouldEqual, uint64(metricSum.DataPoints().At(0).Timestamp())) 282 for k, v := range pipelineGroupEvent.Events[j].GetTags().Iterator() { 283 otTagValue, ok := metricSum.DataPoints().At(0).Attributes().Get(k) 284 convey.So(ok, convey.ShouldBeTrue) 285 convey.So(v, convey.ShouldEqual, otTagValue.AsString()) 286 } 287 288 } 289 } 290 }) 291 }) 292 }) 293 }) 294 } 295 296 func TestConvertPipelineGroupEventsToOtlpTraces(t *testing.T) { 297 convey.Convey("When constructing converter with supported encoding", t, func() { 298 c, err := NewConverter(ProtocolOtlpV1, EncodingNone, nil, nil, &config.GlobalConfig{}) 299 convey.So(err, convey.ShouldBeNil) 300 301 convey.Convey("When the logGroup is generated from files", func() { 302 time := []uint32{1662434209, 1662434487} 303 method := []string{"PUT", "GET"} 304 status := []string{"200", "404"} 305 pipelineGroupEvent := &models.PipelineGroupEvents{ 306 Group: &models.GroupInfo{ 307 Metadata: models.NewMetadata(), 308 Tags: models.NewTags(), 309 }, 310 } 311 312 pipelineGroupEvent.Group.Metadata.Add("__hostname__", "alje834hgf") 313 pipelineGroupEvent.Group.Metadata.Add("__pack_id__", "AEDCFGHNJUIOPLMN-1E") 314 pipelineGroupEvent.Group.Tags.Add(otlp.TagKeyScopeName, "scopename") 315 pipelineGroupEvent.Group.Tags.Add(otlp.TagKeyScopeVersion, "") 316 for i := 0; i < 2; i++ { 317 tags := models.NewTagsWithMap( 318 map[string]string{ 319 "method": method[i], 320 "status": status[i], 321 "__tag__:__path__": "/root/test/origin/example.log", 322 "__log_topic__": "file", 323 "content": "test log content", 324 }, 325 ) 326 327 event := models.NewSpan( 328 "span_name_"+strconv.Itoa(i), 329 "", 330 "", 331 models.SpanKindClient, 332 uint64(time[i]), 333 uint64(time[i]+100), 334 tags, 335 nil, 336 nil, 337 ) 338 pipelineGroupEvent.Events = append(pipelineGroupEvent.Events, event) 339 } 340 341 logs, metrics, traces, err := c.ConvertPipelineGroupEventsToOTLPEventsV1(pipelineGroupEvent) 342 convey.Convey("Then the converted traces should be valid", func() { 343 convey.So(err, convey.ShouldBeNil) 344 convey.So(0, convey.ShouldEqual, logs.ScopeLogs().Len()) 345 convey.So(0, convey.ShouldEqual, metrics.ScopeMetrics().Len()) 346 convey.So(1, convey.ShouldEqual, traces.ScopeSpans().Len()) 347 convey.So(2, convey.ShouldEqual, traces.Resource().Attributes().Len()) 348 349 convey.Convey("Then the traces should be valid", func() { 350 for i := 0; i < traces.ScopeSpans().Len(); i++ { 351 scope := traces.ScopeSpans().At(i) 352 convey.So(scope.Scope().Version(), convey.ShouldEqual, "") 353 convey.So(scope.Scope().Name(), convey.ShouldEqual, "scopename") 354 convey.So(2, convey.ShouldEqual, scope.Spans().Len()) 355 356 for j := 0; j < scope.Spans().Len(); j++ { 357 span := scope.Spans().At(j) 358 convey.So("span_name_"+strconv.Itoa(j), convey.ShouldEqual, span.Name()) 359 event := pipelineGroupEvent.Events[j].(*models.Span) 360 convey.So(event.GetTimestamp(), convey.ShouldEqual, uint64(span.StartTimestamp())) 361 convey.So(event.EndTime, convey.ShouldEqual, uint64(span.EndTimestamp())) 362 363 for k, v := range pipelineGroupEvent.Events[j].GetTags().Iterator() { 364 otTagValue, ok := span.Attributes().Get(k) 365 convey.So(ok, convey.ShouldBeTrue) 366 convey.So(v, convey.ShouldEqual, otTagValue.AsString()) 367 } 368 369 } 370 } 371 }) 372 }) 373 }) 374 }) 375 }