Skip to content

Commit e34ccf8

Browse files
committed
properly format timestamps
1 parent 73ae97d commit e34ccf8

File tree

6 files changed

+86
-12
lines changed

6 files changed

+86
-12
lines changed

exporter/elasticsearchexporter/internal/serializer/otelserializer/profile_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ func TestSerializeProfile(t *testing.T) {
7676
"upsert": map[string]any{},
7777
},
7878
{
79-
"@timestamp": json.Number("0"),
79+
"@timestamp": "1970-01-01T00:00:00Z",
8080
"Stacktrace.count": json.Number("1"),
8181
"Stacktrace.id": "02VzuClbpt_P3xxwox83Ng",
8282
"ecs.version": "1.12.0",

exporter/elasticsearchexporter/internal/serializer/otelserializer/serializeprofiles/model.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
package serializeprofiles // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/elasticsearchexporter/internal/serializer/otelserializer/serializeprofiles"
55

66
import (
7-
"go.opentelemetry.io/collector/pdata/pcommon"
87
"go.opentelemetry.io/ebpf-profiler/libpf"
98
)
109

@@ -36,8 +35,8 @@ type StackPayload struct {
3635
// in the schema mapping.
3736
type StackTraceEvent struct {
3837
EcsVersion
39-
TimeStamp pcommon.Timestamp `json:"@timestamp"`
40-
StackTraceID string `json:"Stacktrace.id"` // 128-bit hash in binary form
38+
TimeStamp unixTime64 `json:"@timestamp"`
39+
StackTraceID string `json:"Stacktrace.id"` // 128-bit hash in binary form
4140

4241
// Event-specific metadata
4342
PodName string `json:"orchestrator.resource.name,omitempty"`

exporter/elasticsearchexporter/internal/serializer/otelserializer/serializeprofiles/transform.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ func stackPayloads(_ pcommon.Resource, _ pcommon.InstrumentationScope, profile p
112112
// Add one event per timestamp and its count value.
113113
for j := 0; j < sample.TimestampsUnixNano().Len(); j++ {
114114
t := sample.TimestampsUnixNano().At(j)
115-
event.TimeStamp = pcommon.Timestamp(t)
115+
event.TimeStamp = newUnixTime64(t)
116116

117117
if j < sample.Value().Len() {
118118
event.Count = uint16(sample.Value().At(j))

exporter/elasticsearchexporter/internal/serializer/otelserializer/serializeprofiles/transform_test.go

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111

1212
"github.com/stretchr/testify/assert"
1313
"github.com/stretchr/testify/require"
14-
"go.opentelemetry.io/collector/pdata/pcommon"
1514
"go.opentelemetry.io/collector/pdata/pprofile"
1615
"go.opentelemetry.io/ebpf-profiler/libpf"
1716
semconv "go.opentelemetry.io/otel/semconv/v1.22.0"
@@ -221,7 +220,7 @@ func TestTransform(t *testing.T) {
221220
{
222221
StackTraceEvent: StackTraceEvent{
223222
EcsVersion: EcsVersion{V: EcsVersionString},
224-
TimeStamp: 42,
223+
TimeStamp: 42000000000,
225224
StackTraceID: wantedTraceID,
226225
Count: 1,
227226
},
@@ -333,7 +332,7 @@ func TestStackPayloads(t *testing.T) {
333332
{
334333
StackTraceEvent: StackTraceEvent{
335334
EcsVersion: EcsVersion{V: EcsVersionString},
336-
TimeStamp: 1,
335+
TimeStamp: 1000000000,
337336
StackTraceID: wantedTraceID,
338337
Count: 1,
339338
},
@@ -418,7 +417,7 @@ func TestStackPayloads(t *testing.T) {
418417
{
419418
StackTraceEvent: StackTraceEvent{
420419
EcsVersion: EcsVersion{V: EcsVersionString},
421-
TimeStamp: 1,
420+
TimeStamp: 1000000000,
422421
StackTraceID: wantedTraceID,
423422
Count: 2,
424423
},
@@ -470,7 +469,7 @@ func TestStackTraceEvent(t *testing.T) {
470469
},
471470
{
472471
name: "sets the timestamp",
473-
timestamp: 1704067273,
472+
timestamp: 1000000000,
474473
buildResourceProfiles: func() pprofile.ResourceProfiles {
475474
rp := pprofile.NewResourceProfiles()
476475
sp := rp.ScopeProfiles().AppendEmpty()
@@ -484,7 +483,7 @@ func TestStackTraceEvent(t *testing.T) {
484483

485484
wantEvent: StackTraceEvent{
486485
EcsVersion: EcsVersion{V: EcsVersionString},
487-
TimeStamp: 1704067273,
486+
TimeStamp: 1000000000000000000,
488487
StackTraceID: stacktraceIDBase64,
489488
Count: 1,
490489
},
@@ -551,7 +550,7 @@ func TestStackTraceEvent(t *testing.T) {
551550
s := p.Sample().At(0)
552551

553552
event := stackTraceEvent(stacktraceIDBase64, p, s)
554-
event.TimeStamp = pcommon.Timestamp(tt.timestamp)
553+
event.TimeStamp = newUnixTime64(tt.timestamp)
555554

556555
assert.Equal(t, tt.wantEvent, event)
557556
})
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package serializeprofiles // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/elasticsearchexporter/internal/serializer/otelserializer/serializeprofiles"
5+
6+
import (
7+
"encoding/json"
8+
"fmt"
9+
"math"
10+
"time"
11+
)
12+
13+
// unixTime64 represents nanoseconds since epoch.
14+
type unixTime64 uint64
15+
16+
// newUnixTime64 creates a unixTime64 from either seconds or nanoseconds since the epoch.
17+
func newUnixTime64(t uint64) unixTime64 {
18+
if t <= math.MaxUint32 {
19+
return unixTime64(t) * 1e9
20+
}
21+
return unixTime64(t)
22+
}
23+
24+
func (t unixTime64) MarshalJSON() ([]byte, error) {
25+
// Nanoseconds, ES does not support 'epoch_nanoseconds' so
26+
// we have to pass it a value formatted as 'strict_date_optional_time_nanos'.
27+
out := []byte(fmt.Sprintf("%q",
28+
time.Unix(0, int64(t)).UTC().Format(time.RFC3339Nano)))
29+
return out, nil
30+
}
31+
32+
// Compile-time interface checks
33+
var _ json.Marshaler = (*unixTime64)(nil)
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package serializeprofiles
5+
6+
import (
7+
"testing"
8+
9+
"github.com/stretchr/testify/assert"
10+
"github.com/stretchr/testify/require"
11+
)
12+
13+
func TestUnixTime64_MarshalJSON(t *testing.T) {
14+
tests := []struct {
15+
name string
16+
time unixTime64
17+
want string
18+
}{
19+
{
20+
name: "zero",
21+
time: newUnixTime64(0),
22+
want: `"1970-01-01T00:00:00Z"`,
23+
},
24+
{
25+
name: "32bit value (assure there is no regression)",
26+
time: newUnixTime64(1710349106),
27+
want: `"2024-03-13T16:58:26Z"`,
28+
},
29+
{
30+
name: "64bit value",
31+
time: newUnixTime64(1710349106864964685),
32+
want: `"2024-03-13T16:58:26.864964685Z"`,
33+
},
34+
}
35+
36+
for _, test := range tests {
37+
t.Run(test.name, func(t *testing.T) {
38+
b, err := test.time.MarshalJSON()
39+
require.NoError(t, err)
40+
assert.Equal(t, test.want, string(b))
41+
})
42+
}
43+
}

0 commit comments

Comments
 (0)