Skip to content

Commit 2c6679c

Browse files
committed
Add ObservedTimestamp to LogRecordData
1 parent 0f74489 commit 2c6679c

7 files changed

Lines changed: 61 additions & 4 deletions

File tree

src/OpenTelemetry.Api/.publicApi/Experimental/PublicAPI.Unshipped.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,5 @@
7373
[OTEL1001]static OpenTelemetry.Logs.LogRecordAttributeList.CreateFromEnumerable(System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string!, object?>>! attributes) -> OpenTelemetry.Logs.LogRecordAttributeList
7474
[OTEL1001]static OpenTelemetry.Logs.LogRecordSeverityExtensions.ToShortName(this OpenTelemetry.Logs.LogRecordSeverity logRecordSeverity) -> string!
7575
[OTEL1001]virtual OpenTelemetry.Logs.LoggerProvider.TryCreateLogger(string? name, out OpenTelemetry.Logs.Logger? logger) -> bool
76+
[OTEL1001]OpenTelemetry.Logs.LogRecordData.ObservedTimestamp.get -> System.DateTime
77+
[OTEL1001]OpenTelemetry.Logs.LogRecordData.ObservedTimestamp.set -> void

src/OpenTelemetry.Api/Logs/LogRecordData.cs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,15 @@ struct LogRecordData
2828
{
2929
internal DateTime TimestampBacking = DateTime.UtcNow;
3030

31+
internal DateTime ObservedTimestampBacking = DateTime.UtcNow;
32+
3133
/// <summary>
3234
/// Initializes a new instance of the <see cref="LogRecordData"/> struct.
3335
/// </summary>
3436
/// <remarks>
3537
/// Notes:
3638
/// <list type="bullet">
37-
/// <item>The <see cref="Timestamp"/> property is initialized to <see
39+
/// <item>The <see cref="Timestamp"/> and <see cref="ObservedTimestamp"/> properties are initialized to <see
3840
/// cref="DateTime.UtcNow"/> automatically.</item>
3941
/// <item>The <see cref="TraceId"/>, <see cref="SpanId"/>, and <see
4042
/// cref="TraceFlags"/> properties will be set using the <see
@@ -50,7 +52,7 @@ public LogRecordData()
5052
/// Initializes a new instance of the <see cref="LogRecordData"/> struct.
5153
/// </summary>
5254
/// <remarks>
53-
/// Note: The <see cref="Timestamp"/> property is initialized to <see
55+
/// Note: <see cref="Timestamp"/> and <see cref="ObservedTimestamp"/> properties are initialized to <see
5456
/// cref="DateTime.UtcNow"/> automatically.
5557
/// </remarks>
5658
/// <param name="activity">Optional <see cref="Activity"/> used to populate
@@ -65,7 +67,7 @@ public LogRecordData(Activity? activity)
6567
/// Initializes a new instance of the <see cref="LogRecordData"/> struct.
6668
/// </summary>
6769
/// <remarks>
68-
/// Note: The <see cref="Timestamp"/> property is initialized to <see
70+
/// Note: <see cref="Timestamp"/> and <see cref="ObservedTimestamp"/> properties are initialized to <see
6971
/// cref="DateTime.UtcNow"/> automatically.
7072
/// </remarks>
7173
/// <param name="activityContext"><see cref="ActivityContext"/> used to
@@ -92,6 +94,20 @@ public DateTime Timestamp
9294
set => this.TimestampBacking = value.Kind == DateTimeKind.Local ? value.ToUniversalTime() : value;
9395
}
9496

97+
/// <summary>
98+
/// Gets or sets the timestamp when the log was recorded by OpenTelemetry's code.
99+
/// </summary>
100+
/// <remarks>
101+
/// Note: If <see cref="ObservedTimestamp"/> is set to a value with <see
102+
/// cref="DateTimeKind.Local"/> it will be automatically converted to
103+
/// UTC using <see cref="DateTime.ToUniversalTime"/>.
104+
/// </remarks>
105+
public DateTime ObservedTimestamp
106+
{
107+
readonly get => this.ObservedTimestampBacking;
108+
set { this.ObservedTimestampBacking = value.Kind == DateTimeKind.Local ? value.ToUniversalTime() : value; }
109+
}
110+
95111
/// <summary>
96112
/// Gets or sets the log <see cref="ActivityTraceId"/>.
97113
/// </summary>

src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Serializer/ProtobufOtlpLogSerializer.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,10 @@ internal static int WriteLogRecord(byte[] buffer, int writePosition, SdkLimitOpt
180180
otlpTagWriterState.WritePosition += ReserveSizeForLength;
181181

182182
var timestamp = (ulong)logRecord.Timestamp.ToUnixTimeNanoseconds();
183+
var observedTimestamp = logRecord.ObservedTimestamp == logRecord.Timestamp ? timestamp
184+
: (ulong)logRecord.ObservedTimestamp.ToUnixTimeNanoseconds();
183185
otlpTagWriterState.WritePosition = ProtobufSerializer.WriteFixed64WithTag(otlpTagWriterState.Buffer, otlpTagWriterState.WritePosition, ProtobufOtlpLogFieldNumberConstants.LogRecord_Time_Unix_Nano, timestamp);
184-
otlpTagWriterState.WritePosition = ProtobufSerializer.WriteFixed64WithTag(otlpTagWriterState.Buffer, otlpTagWriterState.WritePosition, ProtobufOtlpLogFieldNumberConstants.LogRecord_Observed_Time_Unix_Nano, timestamp);
186+
otlpTagWriterState.WritePosition = ProtobufSerializer.WriteFixed64WithTag(otlpTagWriterState.Buffer, otlpTagWriterState.WritePosition, ProtobufOtlpLogFieldNumberConstants.LogRecord_Observed_Time_Unix_Nano, observedTimestamp);
185187

186188
otlpTagWriterState.WritePosition = ProtobufSerializer.WriteEnumWithTag(otlpTagWriterState.Buffer, otlpTagWriterState.WritePosition, ProtobufOtlpLogFieldNumberConstants.LogRecord_Severity_Number, logRecord.Severity.HasValue ? (int)logRecord.Severity : 0);
187189

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
OpenTelemetry.Logs.LogRecord.ObservedTimestamp.get -> System.DateTime
2+
OpenTelemetry.Logs.LogRecord.ObservedTimestamp.set -> void

src/OpenTelemetry/Logs/ILogger/OpenTelemetryLogger.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Except
7171
ref var data = ref record.Data;
7272

7373
data.TimestampBacking = DateTime.UtcNow;
74+
data.ObservedTimestampBacking = data.TimestampBacking;
7475

7576
SetLogRecordSeverityFields(ref data, logLevel);
7677

src/OpenTelemetry/Logs/LogRecord.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ internal LogRecord(
5151
this.Data = new(activity)
5252
{
5353
TimestampBacking = timestamp,
54+
ObservedTimestampBacking = timestamp,
5455

5556
Body = formattedMessage,
5657
};
@@ -114,6 +115,20 @@ public DateTime Timestamp
114115
set => this.Data.Timestamp = value;
115116
}
116117

118+
/// <summary>
119+
/// Gets or sets the observed timestamp.
120+
/// </summary>
121+
/// <remarks>
122+
/// Note: If <see cref="ObservedTimestamp"/> is set to a value with <see
123+
/// cref="DateTimeKind.Local"/> it will be automatically converted to
124+
/// UTC using <see cref="DateTime.ToUniversalTime"/>.
125+
/// </remarks>
126+
public DateTime ObservedTimestamp
127+
{
128+
get => this.Data.ObservedTimestamp;
129+
set => this.Data.ObservedTimestamp = value;
130+
}
131+
117132
/// <summary>
118133
/// Gets or sets the log <see cref="ActivityTraceId"/>.
119134
/// </summary>

test/OpenTelemetry.Api.Tests/Logs/LogRecordDataTests.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,25 @@ record = default;
102102
Assert.Equal(now.ToUniversalTime(), record.Timestamp);
103103
}
104104

105+
[Fact]
106+
public void ObservedTimestampTest()
107+
{
108+
var nowUtc = DateTime.UtcNow;
109+
110+
var record = new LogRecordData();
111+
Assert.True(record.ObservedTimestamp >= nowUtc);
112+
113+
record = default;
114+
Assert.Equal(DateTime.MinValue, record.ObservedTimestamp);
115+
116+
var now = DateTime.Now;
117+
118+
record.ObservedTimestamp = now;
119+
120+
Assert.Equal(DateTimeKind.Utc, record.ObservedTimestamp.Kind);
121+
Assert.Equal(now.ToUniversalTime(), record.ObservedTimestamp);
122+
}
123+
105124
[Fact]
106125
public void SetActivityContextTest()
107126
{

0 commit comments

Comments
 (0)