Skip to content

Commit 46fdb6f

Browse files
authored
Fix log4j timestamp (#3137)
1 parent 775fbd2 commit 46fdb6f

File tree

3 files changed

+152
-1
lines changed

3 files changed

+152
-1
lines changed

agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/SecondEntryPoint.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -648,7 +648,7 @@ private static SdkLoggerProviderBuilder configureLogging(
648648
.setScheduleDelay(getBatchProcessorDelay())
649649
.build();
650650

651-
builder.addLogRecordProcessor(batchLogProcessor);
651+
builder.addLogRecordProcessor(new TimestampingLogRecordProcessor(batchLogProcessor));
652652
}
653653

654654
return builder;
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
package com.microsoft.applicationinsights.agent.internal.init;
5+
6+
import static java.util.concurrent.TimeUnit.SECONDS;
7+
8+
import io.opentelemetry.api.common.AttributeKey;
9+
import io.opentelemetry.api.common.Attributes;
10+
import io.opentelemetry.api.logs.Severity;
11+
import io.opentelemetry.api.trace.SpanContext;
12+
import io.opentelemetry.context.Context;
13+
import io.opentelemetry.sdk.common.CompletableResultCode;
14+
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
15+
import io.opentelemetry.sdk.logs.LogRecordProcessor;
16+
import io.opentelemetry.sdk.logs.ReadWriteLogRecord;
17+
import io.opentelemetry.sdk.logs.data.Body;
18+
import io.opentelemetry.sdk.logs.data.LogRecordData;
19+
import io.opentelemetry.sdk.resources.Resource;
20+
import java.time.Instant;
21+
import javax.annotation.Nullable;
22+
23+
// this is just needed temporarily until
24+
// https://github.com/open-telemetry/opentelemetry-java-instrumentation/pull/8761
25+
class TimestampingLogRecordProcessor implements LogRecordProcessor {
26+
27+
private final LogRecordProcessor delegate;
28+
29+
public TimestampingLogRecordProcessor(LogRecordProcessor delegate) {
30+
this.delegate = delegate;
31+
}
32+
33+
@Override
34+
public void onEmit(Context context, ReadWriteLogRecord logRecord) {
35+
delegate.onEmit(context, new TimestampingReadWriteLogRecord(logRecord, Instant.now()));
36+
}
37+
38+
@Override
39+
public CompletableResultCode shutdown() {
40+
return delegate.shutdown();
41+
}
42+
43+
@Override
44+
public CompletableResultCode forceFlush() {
45+
return delegate.forceFlush();
46+
}
47+
48+
@Override
49+
public void close() {
50+
delegate.close();
51+
}
52+
53+
private static class TimestampingReadWriteLogRecord implements ReadWriteLogRecord {
54+
55+
private final ReadWriteLogRecord delegate;
56+
private final Instant timestamp;
57+
58+
private TimestampingReadWriteLogRecord(ReadWriteLogRecord delegate, Instant timestamp) {
59+
this.delegate = delegate;
60+
this.timestamp = timestamp;
61+
}
62+
63+
@Override
64+
public <T> ReadWriteLogRecord setAttribute(AttributeKey<T> key, T value) {
65+
return delegate.setAttribute(key, value);
66+
}
67+
68+
@Override
69+
public LogRecordData toLogRecordData() {
70+
return new TimestampedLogRecordData(delegate.toLogRecordData(), timestamp);
71+
}
72+
}
73+
74+
private static class TimestampedLogRecordData implements LogRecordData {
75+
76+
private final LogRecordData delegate;
77+
private final Instant timestamp;
78+
79+
private TimestampedLogRecordData(LogRecordData delegate, Instant timestamp) {
80+
this.delegate = delegate;
81+
this.timestamp = timestamp;
82+
}
83+
84+
@Override
85+
public Resource getResource() {
86+
return delegate.getResource();
87+
}
88+
89+
@Override
90+
public InstrumentationScopeInfo getInstrumentationScopeInfo() {
91+
return delegate.getInstrumentationScopeInfo();
92+
}
93+
94+
@Override
95+
public long getTimestampEpochNanos() {
96+
long timestampEpochNanos = delegate.getTimestampEpochNanos();
97+
if (timestampEpochNanos == 0) {
98+
return SECONDS.toNanos(timestamp.getEpochSecond()) + timestamp.getNano();
99+
}
100+
return timestampEpochNanos;
101+
}
102+
103+
@Override
104+
public long getObservedTimestampEpochNanos() {
105+
return delegate.getObservedTimestampEpochNanos();
106+
}
107+
108+
@Override
109+
public SpanContext getSpanContext() {
110+
return delegate.getSpanContext();
111+
}
112+
113+
@Override
114+
public Severity getSeverity() {
115+
return delegate.getSeverity();
116+
}
117+
118+
@Override
119+
@Nullable
120+
public String getSeverityText() {
121+
return delegate.getSeverityText();
122+
}
123+
124+
@Override
125+
public Body getBody() {
126+
return delegate.getBody();
127+
}
128+
129+
@Override
130+
public Attributes getAttributes() {
131+
return delegate.getAttributes();
132+
}
133+
134+
@Override
135+
public int getTotalAttributeCount() {
136+
return delegate.getTotalAttributeCount();
137+
}
138+
}
139+
}

smoke-tests/apps/Log4j2/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/Log4j2Test.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import com.microsoft.applicationinsights.smoketest.schemav2.MessageData;
2222
import com.microsoft.applicationinsights.smoketest.schemav2.RequestData;
2323
import com.microsoft.applicationinsights.smoketest.schemav2.SeverityLevel;
24+
import java.time.Instant;
25+
import java.time.temporal.ChronoUnit;
2426
import java.util.Comparator;
2527
import java.util.List;
2628
import org.junit.jupiter.api.Test;
@@ -45,6 +47,16 @@ void test() throws Exception {
4547
Envelope mdEnvelope3 = mdList.get(2);
4648
Envelope mdEnvelope4 = mdList.get(3);
4749

50+
Instant now = Instant.now();
51+
assertThat(Instant.parse(mdEnvelope1.getTime()))
52+
.isBetween(now.minus(1, ChronoUnit.MINUTES), now);
53+
assertThat(Instant.parse(mdEnvelope2.getTime()))
54+
.isBetween(now.minus(1, ChronoUnit.MINUTES), now);
55+
assertThat(Instant.parse(mdEnvelope3.getTime()))
56+
.isBetween(now.minus(1, ChronoUnit.MINUTES), now);
57+
assertThat(Instant.parse(mdEnvelope4.getTime()))
58+
.isBetween(now.minus(1, ChronoUnit.MINUTES), now);
59+
4860
assertThat(rdEnvelope.getSampleRate()).isNull();
4961
assertThat(mdEnvelope1.getSampleRate()).isNull();
5062
assertThat(mdEnvelope2.getSampleRate()).isNull();

0 commit comments

Comments
 (0)