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  }