Files
Andrzej StencelandGitHub 7e1ed34bbf [exporter/debug] display resource and scope in normal verbosity (#13011)
#### Description

Adds displaying of resource and scope details in `normal` verbosity.

Each resource is represented with one line showing the resource's
details:
- schema URL
- resource attributes

which looks like `ResourceTraces #0 [resource-schema-url]
resource_attr1=value1 attr2=value2`.

Each instrumentation scope is represented by one line showing the
scope's details:
- scope name
- scope version
- scope schema URL
- scope attributes

which looks like `ScopeTraces #0 scope-name@scope-version
[scope-schema-url] scope_attr1=value1 attr2=value2`.

Before:

```console
2025-05-09T19:57:16.332+0200    info    Traces  {"resource": {}, "otelcol.component.id": "debug/normal", "otelcol.component.kind": "exporter", "otelcol.signal": "traces", "resource spans": 1, "spans": 2}
2025-05-09T19:57:16.332+0200    info    okey-dokey-0 ab1030bd4ee554af936542b01d7b4807 1d8c93663d043aa8 net.sock.peer.addr=1.2.3.4 peer.service=telemetrygen-client
lets-go ab1030bd4ee554af936542b01d7b4807 0d238e8a2f97733f net.sock.peer.addr=1.2.3.4 peer.service=telemetrygen-server
        {"resource": {}, "otelcol.component.id": "debug/normal", "otelcol.component.kind": "exporter", "otelcol.signal": "traces"}
```

After:

```console
2025-05-09T19:57:16.332+0200    info    Traces  {"resource": {}, "otelcol.component.id": "debug/normal", "otelcol.component.kind": "exporter", "otelcol.signal": "traces", "resource spans": 1, "spans": 2}
2025-05-09T19:57:16.332+0200    info    ResourceTraces #0 [https://opentelemetry.io/schemas/1.25.0] service.name=telemetrygen
ScopeTraces #0 telemetrygen
okey-dokey-0 ab1030bd4ee554af936542b01d7b4807 1d8c93663d043aa8 net.sock.peer.addr=1.2.3.4 peer.service=telemetrygen-client
lets-go ab1030bd4ee554af936542b01d7b4807 0d238e8a2f97733f net.sock.peer.addr=1.2.3.4 peer.service=telemetrygen-server
        {"resource": {}, "otelcol.component.id": "debug/normal", "otelcol.component.kind": "exporter", "otelcol.signal": "traces"}
```

#### Link to tracking issue

Fixes
https://github.com/open-telemetry/opentelemetry-collector/issues/10515

#### Testing

Updated unit tests.

#### Documentation

Updated example in documentation.
2025-05-21 13:44:35 +00:00

156 lines
5.8 KiB
Go

// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package normal
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/collector/pdata/pcommon"
"go.opentelemetry.io/collector/pdata/plog"
)
func TestMarshalLogs(t *testing.T) {
tests := []struct {
name string
input plog.Logs
expected string
}{
{
name: "empty logs",
input: plog.NewLogs(),
expected: "",
},
{
name: "one log record",
input: func() plog.Logs {
logs := plog.NewLogs()
logRecord := logs.ResourceLogs().AppendEmpty().ScopeLogs().AppendEmpty().LogRecords().AppendEmpty()
logRecord.SetTimestamp(pcommon.NewTimestampFromTime(time.Date(2024, 1, 23, 17, 54, 41, 153, time.UTC)))
logRecord.SetSeverityNumber(plog.SeverityNumberInfo)
logRecord.SetSeverityText("INFO")
logRecord.Body().SetStr("Single line log message")
logRecord.Attributes().PutStr("key1", "value1")
logRecord.Attributes().PutStr("key2", "value2")
return logs
}(),
expected: `ResourceLog #0
ScopeLog #0
Single line log message key1=value1 key2=value2
`,
},
{
name: "one log record with resource and scope attributes",
input: func() plog.Logs {
logs := plog.NewLogs()
resourceLogs := logs.ResourceLogs().AppendEmpty()
resourceLogs.SetSchemaUrl("https://opentelemetry.io/resource-schema-url")
resourceLogs.Resource().Attributes().PutStr("resourceKey1", "resourceValue1")
resourceLogs.Resource().Attributes().PutBool("resourceKey2", false)
scopeLogs := resourceLogs.ScopeLogs().AppendEmpty()
scopeLogs.SetSchemaUrl("http://opentelemetry.io/scope-schema-url")
scopeLogs.Scope().SetName("scope-name")
scopeLogs.Scope().SetVersion("1.2.3")
scopeLogs.Scope().Attributes().PutStr("scopeKey1", "scopeValue1")
scopeLogs.Scope().Attributes().PutBool("scopeKey2", true)
logRecord := scopeLogs.LogRecords().AppendEmpty()
logRecord.SetTimestamp(pcommon.NewTimestampFromTime(time.Date(2024, 1, 23, 17, 54, 41, 153, time.UTC)))
logRecord.SetSeverityNumber(plog.SeverityNumberInfo)
logRecord.SetSeverityText("INFO")
logRecord.Body().SetStr("Single line log message")
logRecord.Attributes().PutStr("key1", "value1")
logRecord.Attributes().PutStr("key2", "value2")
return logs
}(),
expected: `ResourceLog #0 [https://opentelemetry.io/resource-schema-url] resourceKey1=resourceValue1 resourceKey2=false
ScopeLog #0 [email protected] [http://opentelemetry.io/scope-schema-url] scopeKey1=scopeValue1 scopeKey2=true
Single line log message key1=value1 key2=value2
`,
},
{
name: "multiline log",
input: func() plog.Logs {
logs := plog.NewLogs()
logRecord := logs.ResourceLogs().AppendEmpty().ScopeLogs().AppendEmpty().LogRecords().AppendEmpty()
logRecord.SetTimestamp(pcommon.NewTimestampFromTime(time.Date(2024, 1, 23, 17, 54, 41, 153, time.UTC)))
logRecord.SetSeverityNumber(plog.SeverityNumberInfo)
logRecord.SetSeverityText("INFO")
logRecord.Body().SetStr("First line of the log message\n second line of the log message")
logRecord.Attributes().PutStr("key1", "value1")
logRecord.Attributes().PutStr("key2", "value2")
return logs
}(),
expected: `ResourceLog #0
ScopeLog #0
First line of the log message
second line of the log message key1=value1 key2=value2
`,
},
{
name: "two log records",
input: func() plog.Logs {
logs := plog.NewLogs()
logRecords := logs.ResourceLogs().AppendEmpty().ScopeLogs().AppendEmpty().LogRecords()
logRecord := logRecords.AppendEmpty()
logRecord.SetTimestamp(pcommon.NewTimestampFromTime(time.Date(2024, 1, 23, 17, 54, 41, 153, time.UTC)))
logRecord.SetSeverityNumber(plog.SeverityNumberInfo)
logRecord.SetSeverityText("INFO")
logRecord.Body().SetStr("Single line log message")
logRecord.Attributes().PutStr("key1", "value1")
logRecord.Attributes().PutStr("key2", "value2")
logRecord = logRecords.AppendEmpty()
logRecord.Body().SetStr("Multi-line\nlog message")
logRecord.Attributes().PutStr("mykey2", "myvalue2")
logRecord.Attributes().PutStr("mykey1", "myvalue1")
return logs
}(),
expected: `ResourceLog #0
ScopeLog #0
Single line log message key1=value1 key2=value2
Multi-line
log message mykey2=myvalue2 mykey1=myvalue1
`,
},
{
name: "log with maps in body and attributes",
input: func() plog.Logs {
logs := plog.NewLogs()
logRecord := logs.ResourceLogs().AppendEmpty().ScopeLogs().AppendEmpty().LogRecords().AppendEmpty()
logRecord.SetTimestamp(pcommon.NewTimestampFromTime(time.Date(2020, 2, 11, 20, 26, 13, 789, time.UTC)))
logRecord.SetSeverityNumber(plog.SeverityNumberInfo)
logRecord.SetSeverityText("INFO")
body := logRecord.Body().SetEmptyMap()
body.PutStr("app", "CurrencyConverter")
bodyEvent := body.PutEmptyMap("event")
bodyEvent.PutStr("operation", "convert")
bodyEvent.PutStr("result", "success")
conversionAttr := logRecord.Attributes().PutEmptyMap("conversion")
conversionSourceAttr := conversionAttr.PutEmptyMap("source")
conversionSourceAttr.PutStr("currency", "USD")
conversionSourceAttr.PutDouble("amount", 34.22)
conversionDestinationAttr := conversionAttr.PutEmptyMap("destination")
conversionDestinationAttr.PutStr("currency", "EUR")
logRecord.Attributes().PutStr("service", "payments")
return logs
}(),
expected: `ResourceLog #0
ScopeLog #0
{"app":"CurrencyConverter","event":{"operation":"convert","result":"success"}} conversion={"destination":{"currency":"EUR"},"source":{"amount":34.22,"currency":"USD"}} service=payments
`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
output, err := NewNormalLogsMarshaler().MarshalLogs(tt.input)
require.NoError(t, err)
assert.Equal(t, tt.expected, string(output))
})
}
}