123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186 |
- // Copyright The OpenTelemetry Authors
- // SPDX-License-Identifier: Apache-2.0
- package tencentcloudlogserviceexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/tencentcloudlogserviceexporter"
- import (
- "encoding/json"
- "strconv"
- "time"
- "go.opentelemetry.io/collector/pdata/pcommon"
- "go.opentelemetry.io/collector/pdata/plog"
- conventions "go.opentelemetry.io/collector/semconv/v1.6.1"
- "google.golang.org/protobuf/proto"
- cls "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/tencentcloudlogserviceexporter/proto"
- "github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal/traceutil"
- )
- const (
- traceIDField = "traceID"
- spanIDField = "spanID"
- clsLogTimeUnixNano = "timeUnixNano"
- clsLogSeverityNumber = "severityNumber"
- clsLogSeverityText = "severityText"
- clsLogContent = "content"
- clsLogAttribute = "attribute"
- clsLogFlags = "flags"
- clsLogResource = "resource"
- clsLogHost = "host"
- clsLogService = "service"
- // shortcut for "otlp.instrumentation.library.name" "otlp.instrumentation.library.version"
- clsLogInstrumentationName = "otlp.name"
- clsLogInstrumentationVersion = "otlp.version"
- )
- func convertLogs(ld plog.Logs) []*cls.Log {
- clsLogs := make([]*cls.Log, 0, ld.LogRecordCount())
- rls := ld.ResourceLogs()
- for i := 0; i < rls.Len(); i++ {
- rl := rls.At(i)
- ills := rl.ScopeLogs()
- resource := rl.Resource()
- resourceContents := resourceToLogContents(resource)
- for j := 0; j < ills.Len(); j++ {
- ils := ills.At(j)
- instrumentationLibraryContents := instrumentationLibraryToLogContents(ils.Scope())
- logs := ils.LogRecords()
- for j := 0; j < logs.Len(); j++ {
- clsLog := mapLogRecordToLogService(logs.At(j), resourceContents, instrumentationLibraryContents)
- if clsLog != nil {
- clsLogs = append(clsLogs, clsLog)
- }
- }
- }
- }
- return clsLogs
- }
- func resourceToLogContents(resource pcommon.Resource) []*cls.Log_Content {
- attrs := resource.Attributes()
- var hostname, serviceName string
- if host, ok := attrs.Get(conventions.AttributeHostName); ok {
- hostname = host.AsString()
- }
- if service, ok := attrs.Get(conventions.AttributeServiceName); ok {
- serviceName = service.AsString()
- }
- fields := map[string]any{}
- attrs.Range(func(k string, v pcommon.Value) bool {
- if k == conventions.AttributeServiceName || k == conventions.AttributeHostName {
- return true
- }
- fields[k] = v.AsString()
- return true
- })
- attributeBuffer, err := json.Marshal(fields)
- if err != nil {
- return nil
- }
- return []*cls.Log_Content{
- {
- Key: proto.String(clsLogHost),
- Value: proto.String(hostname),
- },
- {
- Key: proto.String(clsLogService),
- Value: proto.String(serviceName),
- },
- {
- Key: proto.String(clsLogResource),
- Value: proto.String(string(attributeBuffer)),
- },
- }
- }
- func instrumentationLibraryToLogContents(scope pcommon.InstrumentationScope) []*cls.Log_Content {
- return []*cls.Log_Content{
- {
- Key: proto.String(clsLogInstrumentationName),
- Value: proto.String(scope.Name()),
- },
- {
- Key: proto.String(clsLogInstrumentationVersion),
- Value: proto.String(scope.Version()),
- },
- }
- }
- func mapLogRecordToLogService(lr plog.LogRecord,
- resourceContents,
- instrumentationLibraryContents []*cls.Log_Content) *cls.Log {
- if lr.Body().Type() == pcommon.ValueTypeEmpty {
- return nil
- }
- var clsLog cls.Log
- // pre alloc, refine if logContent's len > 16
- preAllocCount := 16
- clsLog.Contents = make([]*cls.Log_Content, 0, preAllocCount+len(resourceContents)+len(instrumentationLibraryContents))
- fields := map[string]any{}
- lr.Attributes().Range(func(k string, v pcommon.Value) bool {
- fields[k] = v.AsString()
- return true
- })
- attributeBuffer, err := json.Marshal(fields)
- if err != nil {
- return nil
- }
- contentsBuffer := []*cls.Log_Content{
- {
- Key: proto.String(clsLogTimeUnixNano),
- Value: proto.String(strconv.FormatUint(uint64(lr.Timestamp()), 10)),
- },
- {
- Key: proto.String(clsLogSeverityNumber),
- Value: proto.String(strconv.FormatInt(int64(lr.SeverityNumber()), 10)),
- },
- {
- Key: proto.String(clsLogSeverityText),
- Value: proto.String(lr.SeverityText()),
- },
- {
- Key: proto.String(clsLogAttribute),
- Value: proto.String(string(attributeBuffer)),
- },
- {
- Key: proto.String(clsLogContent),
- Value: proto.String(lr.Body().AsString()),
- },
- {
- Key: proto.String(clsLogFlags),
- Value: proto.String(strconv.FormatUint(uint64(lr.Flags()), 16)),
- },
- {
- Key: proto.String(traceIDField),
- Value: proto.String(traceutil.TraceIDToHexOrEmptyString(lr.TraceID())),
- },
- {
- Key: proto.String(spanIDField),
- Value: proto.String(traceutil.SpanIDToHexOrEmptyString(lr.SpanID())),
- },
- }
- clsLog.Contents = append(clsLog.Contents, resourceContents...)
- clsLog.Contents = append(clsLog.Contents, instrumentationLibraryContents...)
- clsLog.Contents = append(clsLog.Contents, contentsBuffer...)
- if lr.Timestamp() > 0 {
- // convert time nano to time seconds
- clsLog.Time = proto.Int64(int64(lr.Timestamp() / 1000000000))
- } else {
- clsLog.Time = proto.Int64(time.Now().Unix())
- }
- return &clsLog
- }
|