diff --git a/.github/workflows/dotnet-format.yml b/.github/workflows/dotnet-format.yml
index 156989f90f..ba4d12353f 100644
--- a/.github/workflows/dotnet-format.yml
+++ b/.github/workflows/dotnet-format.yml
@@ -21,7 +21,7 @@ jobs:
uses: actions/checkout@v3
- name: Setup .NET 6.0
- uses: actions/setup-dotnet@v2
+ uses: actions/setup-dotnet@v3.0.1
with:
dotnet-version: 6.0.x
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000000..5c19a07622
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,5 @@
+{
+ "cSpell.words": [
+ "fluentdData"
+ ]
+}
diff --git a/build/Common.nonprod.props b/build/Common.nonprod.props
index 6b4934f225..026bf333a4 100644
--- a/build/Common.nonprod.props
+++ b/build/Common.nonprod.props
@@ -20,15 +20,15 @@
Please sort alphabetically.
Refer to https://docs.microsoft.com/en-us/nuget/concepts/package-versioning for semver syntax.
-->
- [0.12.1,0.13)
+ [0.13.2,0.14)
[3.1.2,4.0.0)
[2.3.1,3.0)
- [5.0,6.0)
+ [5.0.0,7.0)
[16.11.0,17.0)
[4.17.2,5.0)
$(OpenTelemetryPkgVer)
[2.4.3,3.0)
- [2.4.1,3.0)
+ [2.4.2,3.0)
diff --git a/build/Common.props b/build/Common.props
index 84eed10c51..2e4d94d967 100644
--- a/build/Common.props
+++ b/build/Common.props
@@ -23,19 +23,19 @@
Please sort alphabetically.
Refer to https://docs.microsoft.com/en-us/nuget/concepts/package-versioning for semver syntax.
-->
- [2.4.0,3.0)
+ [4.2.0,5.0)
[6.0.0]
- [16.11.0]
+ [17.3.2]
[2.1.0,5.0)
[3.1.0,)
- [1.0.0,2.0)
+ [1.0.3,2.0)
[4.2.2,5.0)
- [3.3.2]
- [1.0.0,2.0)
+ [3.3.3]
+ [1.1.1,2.0)
[1.3.1,2.0)
$(OpenTelemetryApiPkgVer)
[2.1.58,3.0)
- [1.2.0-beta.354,2.0)
+ [1.2.0-beta.435,2.0)
diff --git a/src/OpenTelemetry.Exporter.Geneva/GenevaBaseExporter.cs b/src/OpenTelemetry.Exporter.Geneva/GenevaBaseExporter.cs
index 3dc7185074..d38c76267a 100644
--- a/src/OpenTelemetry.Exporter.Geneva/GenevaBaseExporter.cs
+++ b/src/OpenTelemetry.Exporter.Geneva/GenevaBaseExporter.cs
@@ -14,95 +14,9 @@
// limitations under the License.
//
-using System;
-using System.Collections.Generic;
-
namespace OpenTelemetry.Exporter.Geneva;
public abstract class GenevaBaseExporter : BaseExporter
where T : class
{
- internal static readonly IReadOnlyDictionary V21_PART_A_MAPPING = new Dictionary
- {
- // Part A
- [Schema.V21.PartA.IKey] = "env_iKey",
- [Schema.V21.PartA.Name] = "env_name",
- [Schema.V21.PartA.Ver] = "env_ver",
- [Schema.V21.PartA.Time] = "env_time",
- [Schema.V21.PartA.Cv] = "env_cv",
- [Schema.V21.PartA.Epoch] = "env_epoch",
- [Schema.V21.PartA.Flags] = "env_flags",
- [Schema.V21.PartA.PopSample] = "env_popSample",
- [Schema.V21.PartA.SeqNum] = "env_seqNum",
-
- // Part A Application extension
- [Schema.V21.PartA.Extensions.App.Id] = "env_appId",
- [Schema.V21.PartA.Extensions.App.Ver] = "env_appVer",
-
- // Part A Cloud extension
- [Schema.V21.PartA.Extensions.Cloud.Environment] = "env_cloud_environment",
- [Schema.V21.PartA.Extensions.Cloud.Location] = "env_cloud_location",
- [Schema.V21.PartA.Extensions.Cloud.Name] = "env_cloud_name",
- [Schema.V21.PartA.Extensions.Cloud.DeploymentUnit] = "env_cloud_deploymentUnit",
- [Schema.V21.PartA.Extensions.Cloud.Role] = "env_cloud_role",
- [Schema.V21.PartA.Extensions.Cloud.RoleInstance] = "env_cloud_roleInstance",
- [Schema.V21.PartA.Extensions.Cloud.RoleVer] = "env_cloud_roleVer",
- [Schema.V21.PartA.Extensions.Cloud.Ver] = "env_cloud_ver",
-
- // Part A Os extension
- [Schema.V21.PartA.Extensions.Os.Name] = "env_os",
- [Schema.V21.PartA.Extensions.Os.Ver] = "env_osVer",
- };
-
- internal static readonly IReadOnlyDictionary V40_PART_A_MAPPING = new Dictionary
- {
- // Part A
- [Schema.V40.PartA.IKey] = "env_iKey",
- [Schema.V40.PartA.Name] = "env_name",
- [Schema.V40.PartA.Ver] = "env_ver",
- [Schema.V40.PartA.Time] = "env_time",
-
- // Part A Application Extension
- [Schema.V40.PartA.Extensions.App.Id] = "env_app_id",
- [Schema.V40.PartA.Extensions.App.Ver] = "env_app_ver",
-
- // Part A Cloud Extension
- [Schema.V40.PartA.Extensions.Cloud.Role] = "env_cloud_role",
- [Schema.V40.PartA.Extensions.Cloud.RoleInstance] = "env_cloud_roleInstance",
- [Schema.V40.PartA.Extensions.Cloud.RoleVer] = "env_cloud_roleVer",
-
- // Part A Os extension
- [Schema.V40.PartA.Extensions.Os.Name] = "env_os_name",
- [Schema.V40.PartA.Extensions.Os.Ver] = "env_os_ver",
- };
-
- internal static int AddPartAField(byte[] buffer, int cursor, string name, object value)
- {
- if (V40_PART_A_MAPPING.TryGetValue(name, out string replacementKey))
- {
- cursor = MessagePackSerializer.SerializeAsciiString(buffer, cursor, replacementKey);
- }
- else
- {
- cursor = MessagePackSerializer.SerializeUnicodeString(buffer, cursor, name);
- }
-
- cursor = MessagePackSerializer.Serialize(buffer, cursor, value);
- return cursor;
- }
-
- internal static int AddPartAField(byte[] buffer, int cursor, string name, Span value)
- {
- if (V40_PART_A_MAPPING.TryGetValue(name, out string replacementKey))
- {
- cursor = MessagePackSerializer.SerializeAsciiString(buffer, cursor, replacementKey);
- }
- else
- {
- cursor = MessagePackSerializer.SerializeUnicodeString(buffer, cursor, name);
- }
-
- cursor = MessagePackSerializer.SerializeSpan(buffer, cursor, value);
- return cursor;
- }
}
diff --git a/src/OpenTelemetry.Exporter.Geneva/MsgPackExporter/Traces/GenevaExporterHelperExtensions.cs b/src/OpenTelemetry.Exporter.Geneva/GenevaExporterHelperExtensions.cs
similarity index 100%
rename from src/OpenTelemetry.Exporter.Geneva/MsgPackExporter/Traces/GenevaExporterHelperExtensions.cs
rename to src/OpenTelemetry.Exporter.Geneva/GenevaExporterHelperExtensions.cs
diff --git a/src/OpenTelemetry.Exporter.Geneva/GenevaLogExporter.cs b/src/OpenTelemetry.Exporter.Geneva/GenevaLogExporter.cs
new file mode 100644
index 0000000000..b23bd32b10
--- /dev/null
+++ b/src/OpenTelemetry.Exporter.Geneva/GenevaLogExporter.cs
@@ -0,0 +1,73 @@
+//
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+using System;
+using OpenTelemetry.Internal;
+using OpenTelemetry.Logs;
+
+namespace OpenTelemetry.Exporter.Geneva;
+
+public class GenevaLogExporter : GenevaBaseExporter
+{
+ internal bool IsUsingUnixDomainSocket;
+
+ private bool isDisposed;
+
+ private delegate ExportResult ExportLogRecordFunc(in Batch batch);
+
+ private readonly ExportLogRecordFunc exportLogRecord;
+
+ private readonly IDisposable exporter;
+
+ public GenevaLogExporter(GenevaExporterOptions options)
+ {
+ Guard.ThrowIfNull(options);
+ Guard.ThrowIfNullOrWhitespace(options.ConnectionString);
+
+ var msgPackExporter = new MsgPackLogExporter(options);
+ this.IsUsingUnixDomainSocket = msgPackExporter.IsUsingUnixDomainSocket;
+ this.exportLogRecord = (in Batch batch) => msgPackExporter.Export(in batch);
+ this.exporter = msgPackExporter;
+ }
+
+ public override ExportResult Export(in Batch batch)
+ {
+ return this.exportLogRecord(batch);
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (this.isDisposed)
+ {
+ return;
+ }
+
+ if (disposing)
+ {
+ try
+ {
+ this.exporter.Dispose();
+ }
+ catch (Exception ex)
+ {
+ ExporterEventSource.Log.ExporterException("GenevaLogExporter Dispose failed.", ex);
+ }
+ }
+
+ this.isDisposed = true;
+ base.Dispose(disposing);
+ }
+}
diff --git a/src/OpenTelemetry.Exporter.Geneva/MsgPackExporter/Logs/GenevaLoggingExtensions.cs b/src/OpenTelemetry.Exporter.Geneva/GenevaLoggingExtensions.cs
similarity index 100%
rename from src/OpenTelemetry.Exporter.Geneva/MsgPackExporter/Logs/GenevaLoggingExtensions.cs
rename to src/OpenTelemetry.Exporter.Geneva/GenevaLoggingExtensions.cs
diff --git a/src/OpenTelemetry.Exporter.Geneva/GenevaTraceExporter.cs b/src/OpenTelemetry.Exporter.Geneva/GenevaTraceExporter.cs
new file mode 100644
index 0000000000..9c37b6db84
--- /dev/null
+++ b/src/OpenTelemetry.Exporter.Geneva/GenevaTraceExporter.cs
@@ -0,0 +1,73 @@
+//
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+using System;
+using System.Diagnostics;
+using OpenTelemetry.Internal;
+
+namespace OpenTelemetry.Exporter.Geneva;
+
+public class GenevaTraceExporter : GenevaBaseExporter
+{
+ internal readonly bool IsUsingUnixDomainSocket;
+
+ private bool isDisposed;
+
+ private delegate ExportResult ExportActivityFunc(in Batch batch);
+
+ private readonly ExportActivityFunc exportActivity;
+
+ private readonly IDisposable exporter;
+
+ public GenevaTraceExporter(GenevaExporterOptions options)
+ {
+ Guard.ThrowIfNull(options);
+ Guard.ThrowIfNullOrWhitespace(options.ConnectionString);
+
+ var msgPackExporter = new MsgPackTraceExporter(options);
+ this.IsUsingUnixDomainSocket = msgPackExporter.IsUsingUnixDomainSocket;
+ this.exportActivity = (in Batch batch) => msgPackExporter.Export(in batch);
+ this.exporter = msgPackExporter;
+ }
+
+ public override ExportResult Export(in Batch batch)
+ {
+ return this.exportActivity(batch);
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (this.isDisposed)
+ {
+ return;
+ }
+
+ if (disposing)
+ {
+ try
+ {
+ this.exporter.Dispose();
+ }
+ catch (Exception ex)
+ {
+ ExporterEventSource.Log.ExporterException("GenevaTraceExporter Dispose failed.", ex);
+ }
+ }
+
+ this.isDisposed = true;
+ base.Dispose(disposing);
+ }
+}
diff --git a/src/OpenTelemetry.Exporter.Geneva/MsgPackExporter/MsgPackExporter.cs b/src/OpenTelemetry.Exporter.Geneva/MsgPackExporter/MsgPackExporter.cs
new file mode 100644
index 0000000000..f543b01689
--- /dev/null
+++ b/src/OpenTelemetry.Exporter.Geneva/MsgPackExporter/MsgPackExporter.cs
@@ -0,0 +1,75 @@
+//
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+using System;
+using System.Collections.Generic;
+
+namespace OpenTelemetry.Exporter.Geneva;
+
+internal abstract class MsgPackExporter
+{
+ internal static readonly IReadOnlyDictionary V40_PART_A_MAPPING = new Dictionary
+ {
+ // Part A
+ [Schema.V40.PartA.IKey] = "env_iKey",
+ [Schema.V40.PartA.Name] = "env_name",
+ [Schema.V40.PartA.Ver] = "env_ver",
+ [Schema.V40.PartA.Time] = "env_time",
+
+ // Part A Application Extension
+ [Schema.V40.PartA.Extensions.App.Id] = "env_app_id",
+ [Schema.V40.PartA.Extensions.App.Ver] = "env_app_ver",
+
+ // Part A Cloud Extension
+ [Schema.V40.PartA.Extensions.Cloud.Role] = "env_cloud_role",
+ [Schema.V40.PartA.Extensions.Cloud.RoleInstance] = "env_cloud_roleInstance",
+ [Schema.V40.PartA.Extensions.Cloud.RoleVer] = "env_cloud_roleVer",
+
+ // Part A Os extension
+ [Schema.V40.PartA.Extensions.Os.Name] = "env_os_name",
+ [Schema.V40.PartA.Extensions.Os.Ver] = "env_os_ver",
+ };
+
+ protected static int AddPartAField(byte[] buffer, int cursor, string name, object value)
+ {
+ if (V40_PART_A_MAPPING.TryGetValue(name, out string replacementKey))
+ {
+ cursor = MessagePackSerializer.SerializeAsciiString(buffer, cursor, replacementKey);
+ }
+ else
+ {
+ cursor = MessagePackSerializer.SerializeUnicodeString(buffer, cursor, name);
+ }
+
+ cursor = MessagePackSerializer.Serialize(buffer, cursor, value);
+ return cursor;
+ }
+
+ protected static int AddPartAField(byte[] buffer, int cursor, string name, Span value)
+ {
+ if (V40_PART_A_MAPPING.TryGetValue(name, out string replacementKey))
+ {
+ cursor = MessagePackSerializer.SerializeAsciiString(buffer, cursor, replacementKey);
+ }
+ else
+ {
+ cursor = MessagePackSerializer.SerializeUnicodeString(buffer, cursor, name);
+ }
+
+ cursor = MessagePackSerializer.SerializeSpan(buffer, cursor, value);
+ return cursor;
+ }
+}
diff --git a/src/OpenTelemetry.Exporter.Geneva/MsgPackExporter/Logs/GenevaLogExporter.cs b/src/OpenTelemetry.Exporter.Geneva/MsgPackExporter/MsgPackLogExporter.cs
similarity index 95%
rename from src/OpenTelemetry.Exporter.Geneva/MsgPackExporter/Logs/GenevaLogExporter.cs
rename to src/OpenTelemetry.Exporter.Geneva/MsgPackExporter/MsgPackLogExporter.cs
index f6f17a0011..aa60cb88b4 100644
--- a/src/OpenTelemetry.Exporter.Geneva/MsgPackExporter/Logs/GenevaLogExporter.cs
+++ b/src/OpenTelemetry.Exporter.Geneva/MsgPackExporter/MsgPackLogExporter.cs
@@ -1,4 +1,4 @@
-//
+//
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,12 +21,11 @@
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft.Extensions.Logging;
-using OpenTelemetry.Internal;
using OpenTelemetry.Logs;
namespace OpenTelemetry.Exporter.Geneva;
-public class GenevaLogExporter : GenevaBaseExporter
+internal sealed class MsgPackLogExporter : MsgPackExporter, IDisposable
{
private const int BUFFER_SIZE = 65360; // the maximum ETW payload (inclusive)
private const int MaxSanitizedEventNameLength = 50;
@@ -46,11 +45,8 @@ public class GenevaLogExporter : GenevaBaseExporter
private readonly bool shouldPassThruTableMappings;
private bool isDisposed;
- public GenevaLogExporter(GenevaExporterOptions options)
+ public MsgPackLogExporter(GenevaExporterOptions options)
{
- Guard.ThrowIfNull(options);
- Guard.ThrowIfNullOrWhitespace(options.ConnectionString);
-
// TODO: Validate mappings for reserved tablenames etc.
if (options.TableNameMappings != null)
{
@@ -134,7 +130,7 @@ public GenevaLogExporter(GenevaExporterOptions options)
private readonly IReadOnlyDictionary m_tableMappings;
- public override ExportResult Export(in Batch batch)
+ public ExportResult Export(in Batch batch)
{
var result = ExportResult.Success;
foreach (var logRecord in batch)
@@ -154,31 +150,6 @@ public override ExportResult Export(in Batch batch)
return result;
}
- protected override void Dispose(bool disposing)
- {
- if (this.isDisposed)
- {
- return;
- }
-
- if (disposing)
- {
- // DO NOT Dispose m_buffer as it is a static type
- try
- {
- (this.m_dataTransport as IDisposable)?.Dispose();
- this.m_prepopulatedFieldKeys.Clear();
- }
- catch (Exception ex)
- {
- ExporterEventSource.Log.ExporterException("GenevaLogExporter Dispose failed.", ex);
- }
- }
-
- this.isDisposed = true;
- base.Dispose(disposing);
- }
-
internal bool IsUsingUnixDomainSocket
{
get => this.m_dataTransport is UnixDomainSocketDataTransport;
@@ -296,7 +267,8 @@ internal int SerializeLogRecord(LogRecord logRecord)
cntFields += 1;
- cursor = AddPartAField(buffer, cursor, Schema.V40.PartA.Time, timestamp);
+ cursor = MessagePackSerializer.SerializeAsciiString(buffer, cursor, "env_time");
+ cursor = MessagePackSerializer.SerializeUtcDateTime(buffer, cursor, timestamp); // LogRecord.Timestamp should already be converted to UTC format in the SDK
cntFields += 1;
// Part A - dt extension
@@ -547,4 +519,25 @@ private static int SerializeSanitizedCategoryName(byte[] buffer, int cursor, str
return cursor;
}
+
+ public void Dispose()
+ {
+ if (this.isDisposed)
+ {
+ return;
+ }
+
+ // DO NOT Dispose m_buffer as it is a static type
+ try
+ {
+ (this.m_dataTransport as IDisposable)?.Dispose();
+ this.m_prepopulatedFieldKeys.Clear();
+ }
+ catch (Exception ex)
+ {
+ ExporterEventSource.Log.ExporterException("MsgPackLogExporter Dispose failed.", ex);
+ }
+
+ this.isDisposed = true;
+ }
}
diff --git a/src/OpenTelemetry.Exporter.Geneva/MsgPackExporter/Traces/GenevaTraceExporter.cs b/src/OpenTelemetry.Exporter.Geneva/MsgPackExporter/MsgPackTraceExporter.cs
similarity index 95%
rename from src/OpenTelemetry.Exporter.Geneva/MsgPackExporter/Traces/GenevaTraceExporter.cs
rename to src/OpenTelemetry.Exporter.Geneva/MsgPackExporter/MsgPackTraceExporter.cs
index 5ae7849df1..bdced95e7d 100644
--- a/src/OpenTelemetry.Exporter.Geneva/MsgPackExporter/Traces/GenevaTraceExporter.cs
+++ b/src/OpenTelemetry.Exporter.Geneva/MsgPackExporter/MsgPackTraceExporter.cs
@@ -1,4 +1,4 @@
-//
+//
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,17 +20,13 @@
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
-using OpenTelemetry.Internal;
namespace OpenTelemetry.Exporter.Geneva;
-public class GenevaTraceExporter : GenevaBaseExporter
+internal sealed class MsgPackTraceExporter : MsgPackExporter, IDisposable
{
- public GenevaTraceExporter(GenevaExporterOptions options)
+ public MsgPackTraceExporter(GenevaExporterOptions options)
{
- Guard.ThrowIfNull(options);
- Guard.ThrowIfNullOrWhitespace(options.ConnectionString);
-
var partAName = "Span";
if (options.TableNameMappings != null
&& options.TableNameMappings.TryGetValue("Span", out var customTableName))
@@ -144,7 +140,7 @@ public GenevaTraceExporter(GenevaExporterOptions options)
Buffer.BlockCopy(buffer, 0, this.m_bufferEpilogue, 0, cursor - 0);
}
- public override ExportResult Export(in Batch batch)
+ public ExportResult Export(in Batch batch)
{
// Note: The MessagePackSerializer takes way less time / memory than creating the activity itself.
// This makes the short-circuit check less useful.
@@ -173,30 +169,6 @@ public override ExportResult Export(in Batch batch)
return result;
}
- protected override void Dispose(bool disposing)
- {
- if (this.isDisposed)
- {
- return;
- }
-
- if (disposing)
- {
- try
- {
- (this.m_dataTransport as IDisposable)?.Dispose();
- this.m_buffer.Dispose();
- }
- catch (Exception ex)
- {
- ExporterEventSource.Log.ExporterException("GenevaTraceExporter Dispose failed.", ex);
- }
- }
-
- this.isDisposed = true;
- base.Dispose(disposing);
- }
-
internal bool IsUsingUnixDomainSocket
{
get => this.m_dataTransport is UnixDomainSocketDataTransport;
@@ -403,6 +375,26 @@ internal int SerializeActivity(Activity activity)
return cursor;
}
+ public void Dispose()
+ {
+ if (this.isDisposed)
+ {
+ return;
+ }
+
+ try
+ {
+ (this.m_dataTransport as IDisposable)?.Dispose();
+ this.m_buffer.Dispose();
+ }
+ catch (Exception ex)
+ {
+ ExporterEventSource.Log.ExporterException("MsgPackTraceExporter Dispose failed.", ex);
+ }
+
+ this.isDisposed = true;
+ }
+
private const int BUFFER_SIZE = 65360; // the maximum ETW payload (inclusive)
private readonly ThreadLocal m_buffer = new ThreadLocal(() => null);
diff --git a/src/OpenTelemetry.Exporter.Stackdriver/CHANGELOG.md b/src/OpenTelemetry.Exporter.Stackdriver/CHANGELOG.md
index e492e044af..ec1f06889a 100644
--- a/src/OpenTelemetry.Exporter.Stackdriver/CHANGELOG.md
+++ b/src/OpenTelemetry.Exporter.Stackdriver/CHANGELOG.md
@@ -2,6 +2,9 @@
## Unreleased
+* Fix the issue of incorrect handling of null attributes.
+ ([#566](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/566))
+
## 1.0.0-beta.3
Released 2022-Jul-22
diff --git a/src/OpenTelemetry.Instrumentation.AWSLambda/AWSLambdaWrapper.cs b/src/OpenTelemetry.Instrumentation.AWSLambda/AWSLambdaWrapper.cs
index c2995f5231..9359fc17b5 100644
--- a/src/OpenTelemetry.Instrumentation.AWSLambda/AWSLambdaWrapper.cs
+++ b/src/OpenTelemetry.Instrumentation.AWSLambda/AWSLambdaWrapper.cs
@@ -17,6 +17,7 @@
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
+using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Amazon.Lambda.Core;
@@ -68,10 +69,7 @@ public static TResult Trace(
ILambdaContext context,
ActivityContext parentContext = default)
{
- TResult result = default;
- Action action = () => result = lambdaHandler(input, context);
- TraceInternal(tracerProvider, action, input, context, parentContext);
- return result;
+ return TraceInternal(tracerProvider, lambdaHandler, input, context, parentContext);
}
///
@@ -95,8 +93,12 @@ public static void Trace(
ILambdaContext context,
ActivityContext parentContext = default)
{
- Action action = () => lambdaHandler(input, context);
- TraceInternal(tracerProvider, action, input, context, parentContext);
+ Func func = (input, context) =>
+ {
+ lambdaHandler(input, context);
+ return null;
+ };
+ TraceInternal(tracerProvider, func, input, context, parentContext);
}
///
@@ -121,8 +123,12 @@ public static Task TraceAsync(
ILambdaContext context,
ActivityContext parentContext = default)
{
- Func action = async () => await lambdaHandler(input, context);
- return TraceInternalAsync(tracerProvider, action, input, context, parentContext);
+ Func> func = async (input, context) =>
+ {
+ await lambdaHandler(input, context);
+ return null;
+ };
+ return TraceInternalAsync(tracerProvider, func, input, context, parentContext);
}
///
@@ -141,17 +147,14 @@ public static Task TraceAsync(
/// unless X-Ray propagation is disabled in the configuration for this wrapper.
///
/// Task of result.
- public static async Task TraceAsync(
+ public static Task TraceAsync(
TracerProvider tracerProvider,
Func> lambdaHandler,
TInput input,
ILambdaContext context,
ActivityContext parentContext = default)
{
- TResult result = default;
- Func action = async () => result = await lambdaHandler(input, context);
- await TraceInternalAsync(tracerProvider, action, input, context, parentContext);
- return result;
+ return TraceInternalAsync(tracerProvider, lambdaHandler, input, context, parentContext);
}
#pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters
@@ -167,9 +170,12 @@ internal static Activity OnFunctionStart(TInput input, ILambdaContext co
}
}
- var tags = AWSLambdaUtils.GetFunctionTags(input, context);
+ var functionTags = AWSLambdaUtils.GetFunctionTags(input, context);
+ var httpTags = AWSLambdaHttpUtils.GetHttpTags(input);
+
+ // We assume that functionTags and httpTags have no intersection.
var activityName = AWSLambdaUtils.GetFunctionName(context) ?? "AWS Lambda Invoke";
- var activity = AWSLambdaActivitySource.StartActivity(activityName, ActivityKind.Server, parentContext, tags);
+ var activity = AWSLambdaActivitySource.StartActivity(activityName, ActivityKind.Server, parentContext, functionTags.Concat(httpTags));
return activity;
}
@@ -197,51 +203,55 @@ private static void OnException(Activity activity, Exception exception)
}
}
- private static void TraceInternal(
+ private static TResult TraceInternal(
TracerProvider tracerProvider,
- Action handler,
+ Func handler,
TInput input,
ILambdaContext context,
ActivityContext parentContext = default)
{
- var lambdaActivity = OnFunctionStart(input, context, parentContext);
+ var activity = OnFunctionStart(input, context, parentContext);
try
{
- handler();
+ var result = handler(input, context);
+ AWSLambdaHttpUtils.SetHttpTagsFromResult(activity, result);
+ return result;
}
catch (Exception ex)
{
- OnException(lambdaActivity, ex);
+ OnException(activity, ex);
throw;
}
finally
{
- OnFunctionStop(lambdaActivity, tracerProvider);
+ OnFunctionStop(activity, tracerProvider);
}
}
- private static async Task TraceInternalAsync(
+ private static async Task TraceInternalAsync(
TracerProvider tracerProvider,
- Func handlerAsync,
+ Func> handlerAsync,
TInput input,
ILambdaContext context,
ActivityContext parentContext = default)
{
- var lambdaActivity = OnFunctionStart(input, context, parentContext);
+ var activity = OnFunctionStart(input, context, parentContext);
try
{
- await handlerAsync();
+ var result = await handlerAsync(input, context);
+ AWSLambdaHttpUtils.SetHttpTagsFromResult(activity, result);
+ return result;
}
catch (Exception ex)
{
- OnException(lambdaActivity, ex);
+ OnException(activity, ex);
throw;
}
finally
{
- OnFunctionStop(lambdaActivity, tracerProvider);
+ OnFunctionStop(activity, tracerProvider);
}
}
}
diff --git a/src/OpenTelemetry.Instrumentation.AWSLambda/CHANGELOG.md b/src/OpenTelemetry.Instrumentation.AWSLambda/CHANGELOG.md
index db388af70c..729760a2cf 100644
--- a/src/OpenTelemetry.Instrumentation.AWSLambda/CHANGELOG.md
+++ b/src/OpenTelemetry.Instrumentation.AWSLambda/CHANGELOG.md
@@ -2,6 +2,9 @@
## Unreleased
+* Add HTTP server span attributes for API Gateway triggers
+ ([#626](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/626))
+
## 1.1.0-beta.2
Release PR: [#590](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/590)
diff --git a/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaHttpUtils.cs b/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaHttpUtils.cs
new file mode 100644
index 0000000000..25adefc903
--- /dev/null
+++ b/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaHttpUtils.cs
@@ -0,0 +1,136 @@
+//
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Text;
+using System.Web;
+using Amazon.Lambda.APIGatewayEvents;
+using OpenTelemetry.Trace;
+
+namespace OpenTelemetry.Instrumentation.AWSLambda.Implementation
+{
+ internal class AWSLambdaHttpUtils
+ {
+ // x-forwarded-... headers are described here https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/x-forwarded-headers.html
+ private const string HeaderXForwardedProto = "x-forwarded-proto";
+ private const string HeaderHost = "host";
+
+ internal static IEnumerable> GetHttpTags(TInput input)
+ {
+ var tags = new List>();
+
+ string httpScheme = null;
+ string httpTarget = null;
+ string httpMethod = null;
+ string hostName = null;
+ int? hostPort = null;
+
+ switch (input)
+ {
+ case APIGatewayProxyRequest request:
+ httpScheme = AWSLambdaUtils.GetHeaderValues(request, HeaderXForwardedProto)?.LastOrDefault();
+ httpTarget = string.Concat(request.RequestContext?.Path ?? string.Empty, GetQueryString(request));
+ httpMethod = request.HttpMethod;
+ var hostHeader = AWSLambdaUtils.GetHeaderValues(request, HeaderHost)?.LastOrDefault();
+ (hostName, hostPort) = GetHostAndPort(httpScheme, hostHeader);
+ break;
+ case APIGatewayHttpApiV2ProxyRequest requestV2:
+ httpScheme = AWSLambdaUtils.GetHeaderValues(requestV2, HeaderXForwardedProto)?.LastOrDefault();
+ httpTarget = string.Concat(requestV2.RawPath ?? string.Empty, GetQueryString(requestV2));
+ httpMethod = requestV2.RequestContext?.Http?.Method;
+ var hostHeaderV2 = AWSLambdaUtils.GetHeaderValues(requestV2, HeaderHost)?.LastOrDefault();
+ (hostName, hostPort) = GetHostAndPort(httpScheme, hostHeaderV2);
+ break;
+ }
+
+ tags.AddTagIfNotNull(SemanticConventions.AttributeHttpScheme, httpScheme);
+ tags.AddTagIfNotNull(SemanticConventions.AttributeHttpTarget, httpTarget);
+ tags.AddTagIfNotNull(SemanticConventions.AttributeHttpMethod, httpMethod);
+ tags.AddTagIfNotNull(SemanticConventions.AttributeNetHostName, hostName);
+ tags.AddTagIfNotNull(SemanticConventions.AttributeNetHostPort, hostPort);
+
+ return tags;
+ }
+
+ internal static void SetHttpTagsFromResult(Activity activity, object result)
+ {
+ switch (result)
+ {
+ case APIGatewayProxyResponse response:
+ activity.SetTag(SemanticConventions.AttributeHttpStatusCode, response.StatusCode);
+ break;
+ case APIGatewayHttpApiV2ProxyResponse responseV2:
+ activity.SetTag(SemanticConventions.AttributeHttpStatusCode, responseV2.StatusCode);
+ break;
+ }
+ }
+
+ internal static string GetQueryString(APIGatewayProxyRequest request)
+ {
+ if (request.MultiValueQueryStringParameters == null)
+ {
+ return string.Empty;
+ }
+
+ var queryString = new StringBuilder();
+ var separator = '?';
+ foreach (var parameterKvp in request.MultiValueQueryStringParameters)
+ {
+ // Multiple values for the same parameter will be added to query
+ // as ampersand separated: name=value1&name=value2
+ foreach (var value in parameterKvp.Value)
+ {
+ queryString.Append(separator)
+ .Append(HttpUtility.UrlEncode(parameterKvp.Key))
+ .Append("=")
+ .Append(HttpUtility.UrlEncode(value));
+ separator = '&';
+ }
+ }
+
+ return queryString.ToString();
+ }
+
+ internal static string GetQueryString(APIGatewayHttpApiV2ProxyRequest request) =>
+ string.IsNullOrEmpty(request.RawQueryString) ? string.Empty : "?" + request.RawQueryString;
+
+ internal static (string Host, int? Port) GetHostAndPort(string httpScheme, string hostHeader)
+ {
+ if (hostHeader == null)
+ {
+ return (null, null);
+ }
+
+ var hostAndPort = hostHeader.Split(new char[] { ':' }, 2);
+ if (hostAndPort.Length > 1)
+ {
+ var host = hostAndPort[0];
+ return int.TryParse(hostAndPort[1], out var port)
+ ? (host, port)
+ : (host, null);
+ }
+ else
+ {
+ return (hostAndPort[0], GetDefaultPort(httpScheme));
+ }
+ }
+
+ private static int? GetDefaultPort(string httpScheme) =>
+ httpScheme == "https" ? 443 : httpScheme == "http" ? 80 : null;
+ }
+}
diff --git a/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs b/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs
index c2ae886f0d..75d0ba2a63 100644
--- a/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs
+++ b/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs
@@ -137,6 +137,30 @@ internal static IEnumerable> GetFunctionTags GetHeaderValues(APIGatewayProxyRequest request, string name)
+ {
+ var multiValueHeader = request.MultiValueHeaders?.GetValueByKeyIgnoringCase(name);
+ if (multiValueHeader != null)
+ {
+ return multiValueHeader;
+ }
+
+ var headerValue = request.Headers?.GetValueByKeyIgnoringCase(name);
+
+ return headerValue != null ? new[] { headerValue } : null;
+ }
+
+ internal static IEnumerable GetHeaderValues(APIGatewayHttpApiV2ProxyRequest request, string name)
+ {
+ var headerValue = GetHeaderValue(request, name);
+
+ // Multiple values for the same header will be separated by a comma.
+ return headerValue?.Split(',');
+ }
+
+ private static string GetHeaderValue(APIGatewayHttpApiV2ProxyRequest request, string name) =>
+ request.Headers?.GetValueByKeyIgnoringCase(name);
+
private static string GetAccountId(string functionArn)
{
// The fifth item of function arn: https://github.com/open-telemetry/opentelemetry-specification/blob/86aeab1e0a7e6c67be09c7f15ff25063ee6d2b5c/specification/trace/semantic_conventions/instrumentation/aws-lambda.md#all-triggers
@@ -167,16 +191,11 @@ private static string GetFaasId(string functionArn)
return faasId;
}
- private static string GetFaasTrigger(TInput input)
- {
- var trigger = "other";
- if (input is APIGatewayProxyRequest || input is APIGatewayHttpApiV2ProxyRequest)
- {
- trigger = "http";
- }
+ private static string GetFaasTrigger(TInput input) =>
+ IsHttpRequest(input) ? "http" : "other";
- return trigger;
- }
+ private static bool IsHttpRequest(TInput input) =>
+ input is APIGatewayProxyRequest || input is APIGatewayHttpApiV2ProxyRequest;
private static ActivityContext ParseXRayTraceHeader(string rawHeader)
{
@@ -190,27 +209,4 @@ private static ActivityContext ParseXRayTraceHeader(string rawHeader)
var propagationContext = xrayPropagator.Extract(default, carrier, Getter);
return propagationContext.ActivityContext;
}
-
- private static IEnumerable GetHeaderValues(APIGatewayProxyRequest request, string name)
- {
- if (request.MultiValueHeaders != null &&
- request.MultiValueHeaders.TryGetValue(name, out var values))
- {
- return values;
- }
-
- return null;
- }
-
- private static IEnumerable GetHeaderValues(APIGatewayHttpApiV2ProxyRequest request, string name)
- {
- if (request.Headers != null &&
- request.Headers.TryGetValue(name, out var header))
- {
- // Multiple values for the same header will be separated by a comma.
- return header?.Split(',');
- }
-
- return null;
- }
}
diff --git a/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/CommonExtensions.cs b/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/CommonExtensions.cs
new file mode 100644
index 0000000000..d82ebfad5e
--- /dev/null
+++ b/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/CommonExtensions.cs
@@ -0,0 +1,57 @@
+//
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+using System;
+using System.Collections.Generic;
+
+namespace OpenTelemetry.Instrumentation.AWSLambda.Implementation
+{
+ internal static class CommonExtensions
+ {
+ internal static void AddTagIfNotNull(this List> tags, string tagName, object tagValue)
+ {
+ if (tagValue != null)
+ {
+ tags.Add(new(tagName, tagValue));
+ }
+ }
+
+ internal static T GetValueByKeyIgnoringCase(this IDictionary dict, string key)
+ {
+ // TODO: there may be opportunities for performance improvements of this method.
+
+ // We had to introduce case-insensitive headers search as can't fully rely on
+ // AWS documentation stating that expected headers are lower-case. AWS test
+ // console offers JSON example with camel case header names.
+ // See X-Forwarded-Proto or X-Forwarded-Port for example.
+
+ if (dict == null)
+ {
+ return default;
+ }
+
+ foreach (var kvp in dict)
+ {
+ if (string.Equals(kvp.Key, key, StringComparison.OrdinalIgnoreCase))
+ {
+ return kvp.Value;
+ }
+ }
+
+ return default;
+ }
+ }
+}
diff --git a/src/OpenTelemetry.Instrumentation.AWSLambda/OpenTelemetry.Instrumentation.AWSLambda.csproj b/src/OpenTelemetry.Instrumentation.AWSLambda/OpenTelemetry.Instrumentation.AWSLambda.csproj
index 239fb3e9f1..4afae25088 100644
--- a/src/OpenTelemetry.Instrumentation.AWSLambda/OpenTelemetry.Instrumentation.AWSLambda.csproj
+++ b/src/OpenTelemetry.Instrumentation.AWSLambda/OpenTelemetry.Instrumentation.AWSLambda.csproj
@@ -17,6 +17,7 @@
+
diff --git a/src/OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule/CHANGELOG.md b/src/OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule/CHANGELOG.md
index ed4038c5fc..bd3006b278 100644
--- a/src/OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule/CHANGELOG.md
+++ b/src/OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule/CHANGELOG.md
@@ -2,6 +2,13 @@
## Unreleased
+## 1.0.0-rc9.6
+
+Released 2022-Sep-28
+
+* Update `OpenTelemetry.Api` to `1.3.1`.
+([#665](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/665))
+
## 1.0.0-rc9.5 (source code moved to contrib repo)
Released 2022-Jun-21
diff --git a/src/OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule/OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule.csproj b/src/OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule/OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule.csproj
index 35ea9547d7..64ed2d64c2 100644
--- a/src/OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule/OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule.csproj
+++ b/src/OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule/OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule.csproj
@@ -1,7 +1,7 @@
- net462
+ $(NetFrameworkMinimumSupportedVersion)
A module that instruments incoming request with System.Diagnostics.Activity and notifies listeners with DiagnosticsSource.
$(PackageTags);distributed-tracing;AspNet;MVC;WebAPI
Instrumentation.AspNet.TelemetryHttpModule-
@@ -23,6 +23,6 @@
-
+
diff --git a/src/OpenTelemetry.Instrumentation.AspNet/CHANGELOG.md b/src/OpenTelemetry.Instrumentation.AspNet/CHANGELOG.md
index 71a4bfa708..ca186294be 100644
--- a/src/OpenTelemetry.Instrumentation.AspNet/CHANGELOG.md
+++ b/src/OpenTelemetry.Instrumentation.AspNet/CHANGELOG.md
@@ -2,6 +2,13 @@
## Unreleased
+## 1.0.0-rc9.6
+
+Released 2022-Sep-28
+
+* Migrate to native Activity `Status` and `StatusDesciption`.
+ ([#651](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/651))
+
## 1.0.0-rc9.5 (source code moved to contrib repo)
Released 2022-Jun-21
diff --git a/src/OpenTelemetry.Instrumentation.AspNet/Implementation/HttpInListener.cs b/src/OpenTelemetry.Instrumentation.AspNet/Implementation/HttpInListener.cs
index 716b9c0136..a8c1ddb9a4 100644
--- a/src/OpenTelemetry.Instrumentation.AspNet/Implementation/HttpInListener.cs
+++ b/src/OpenTelemetry.Instrumentation.AspNet/Implementation/HttpInListener.cs
@@ -128,9 +128,9 @@ private void OnStopActivity(Activity activity, HttpContext context)
activity.SetTag(SemanticConventions.AttributeHttpStatusCode, response.StatusCode);
- if (activity.GetStatus().StatusCode == StatusCode.Unset)
+ if (activity.Status == ActivityStatusCode.Unset)
{
- activity.SetStatus(SpanHelper.ResolveSpanStatusForHttpStatusCode(activity.Kind, response.StatusCode));
+ activity.SetStatus(SpanHelper.ResolveActivityStatusForHttpStatusCode(activity.Kind, response.StatusCode));
}
var routeData = context.Request.RequestContext.RouteData;
@@ -181,7 +181,7 @@ private void OnException(Activity activity, HttpContext context, Exception excep
activity.RecordException(exception);
}
- activity.SetStatus(Status.Error.WithDescription(exception.Message));
+ activity.SetStatus(ActivityStatusCode.Error, exception.Message);
try
{
diff --git a/src/OpenTelemetry.Instrumentation.AspNet/OpenTelemetry.Instrumentation.AspNet.csproj b/src/OpenTelemetry.Instrumentation.AspNet/OpenTelemetry.Instrumentation.AspNet.csproj
index 03f775a3d7..ea25e6d359 100644
--- a/src/OpenTelemetry.Instrumentation.AspNet/OpenTelemetry.Instrumentation.AspNet.csproj
+++ b/src/OpenTelemetry.Instrumentation.AspNet/OpenTelemetry.Instrumentation.AspNet.csproj
@@ -1,7 +1,7 @@
- net462
+ $(NetFrameworkMinimumSupportedVersion)
ASP.NET instrumentation for OpenTelemetry .NET
$(PackageTags);distributed-tracing;AspNet;MVC;WebAPI
true
@@ -14,7 +14,6 @@
-
diff --git a/src/OpenTelemetry.Instrumentation.AspNet/SpanHelper.cs b/src/OpenTelemetry.Instrumentation.AspNet/SpanHelper.cs
new file mode 100644
index 0000000000..14e6bc4e2c
--- /dev/null
+++ b/src/OpenTelemetry.Instrumentation.AspNet/SpanHelper.cs
@@ -0,0 +1,43 @@
+//
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+using System.Diagnostics;
+
+namespace OpenTelemetry.Instrumentation.AspNet;
+
+///
+/// A collection of helper methods to be used when building spans.
+///
+internal static class SpanHelper
+{
+ ///
+ /// Helper method that populates Activity Status from http status code according
+ /// to https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/http.md#status.
+ ///
+ /// The span kind.
+ /// Http status code.
+ /// Resolved span for the Http status code.
+ public static ActivityStatusCode ResolveActivityStatusForHttpStatusCode(ActivityKind kind, int httpStatusCode)
+ {
+ var upperBound = kind == ActivityKind.Client ? 399 : 499;
+ if (httpStatusCode >= 100 && httpStatusCode <= upperBound)
+ {
+ return ActivityStatusCode.Unset;
+ }
+
+ return ActivityStatusCode.Error;
+ }
+}
diff --git a/src/OpenTelemetry.Instrumentation.Process/MeterProviderBuilderExtensions.cs b/src/OpenTelemetry.Instrumentation.Process/MeterProviderBuilderExtensions.cs
index 516945ebd1..223808b4a4 100644
--- a/src/OpenTelemetry.Instrumentation.Process/MeterProviderBuilderExtensions.cs
+++ b/src/OpenTelemetry.Instrumentation.Process/MeterProviderBuilderExtensions.cs
@@ -41,7 +41,7 @@ public static MeterProviderBuilder AddProcessInstrumentation(
configure?.Invoke(options);
var instrumentation = new ProcessMetrics(options);
- builder.AddMeter(ProcessMetrics.MeterInstance.Name);
+ builder.AddMeter(instrumentation.MeterInstance.Name);
return builder.AddInstrumentation(() => instrumentation);
}
}
diff --git a/src/OpenTelemetry.Instrumentation.Process/ProcessMetrics.cs b/src/OpenTelemetry.Instrumentation.Process/ProcessMetrics.cs
index 563ff11452..30c9b2a7d8 100644
--- a/src/OpenTelemetry.Instrumentation.Process/ProcessMetrics.cs
+++ b/src/OpenTelemetry.Instrumentation.Process/ProcessMetrics.cs
@@ -14,48 +14,90 @@
// limitations under the License.
//
+using System.Collections.Generic;
using System.Diagnostics.Metrics;
using System.Reflection;
using Diagnostics = System.Diagnostics;
namespace OpenTelemetry.Instrumentation.Process;
-internal class ProcessMetrics
+internal sealed class ProcessMetrics
{
internal static readonly AssemblyName AssemblyName = typeof(ProcessMetrics).Assembly.GetName();
- internal static readonly Meter MeterInstance = new(AssemblyName.Name, AssemblyName.Version.ToString());
- private static readonly Diagnostics.Process CurrentProcess = Diagnostics.Process.GetCurrentProcess();
+ internal readonly Meter MeterInstance = new(AssemblyName.Name, AssemblyName.Version.ToString());
- static ProcessMetrics()
+ private readonly Diagnostics.Process currentProcess = Diagnostics.Process.GetCurrentProcess();
+ private double? memoryUsage;
+ private double? virtualMemoryUsage;
+ private double? userProcessorTime;
+ private double? privilegedProcessorTime;
+
+ public ProcessMetrics(ProcessInstrumentationOptions options)
{
// TODO: change to ObservableUpDownCounter
- MeterInstance.CreateObservableGauge(
+ this.MeterInstance.CreateObservableGauge(
"process.memory.usage",
() =>
{
- CurrentProcess.Refresh();
- return CurrentProcess.WorkingSet64;
+ if (!this.memoryUsage.HasValue)
+ {
+ this.Snapshot();
+ }
+
+ var value = this.memoryUsage.Value;
+ this.memoryUsage = null;
+ return value;
},
unit: "By",
- description: "The amount of physical memory in use.");
+ description: "The amount of physical memory allocated for this process.");
// TODO: change to ObservableUpDownCounter
- MeterInstance.CreateObservableGauge(
+ this.MeterInstance.CreateObservableGauge(
"process.memory.virtual",
() =>
{
- CurrentProcess.Refresh();
- return CurrentProcess.VirtualMemorySize64;
+ if (!this.virtualMemoryUsage.HasValue)
+ {
+ this.Snapshot();
+ }
+
+ var value = this.virtualMemoryUsage.Value;
+ this.virtualMemoryUsage = null;
+ return value;
},
unit: "By",
- description: "The amount of committed virtual memory.");
+ description: "The amount of virtual memory allocated for this process that cannot be shared with other processes.");
+
+ this.MeterInstance.CreateObservableCounter(
+ "process.cpu.time",
+ () =>
+ {
+ if (!this.userProcessorTime.HasValue || !this.privilegedProcessorTime.HasValue)
+ {
+ this.Snapshot();
+ }
+
+ var userProcessorTimeValue = this.userProcessorTime.Value;
+ var privilegedProcessorTimeValue = this.privilegedProcessorTime.Value;
+ this.userProcessorTime = null;
+ this.privilegedProcessorTime = null;
+
+ return new[]
+ {
+ new Measurement(userProcessorTimeValue, new KeyValuePair("state", "user")),
+ new Measurement(privilegedProcessorTimeValue, new KeyValuePair("state", "system")),
+ };
+ },
+ unit: "s",
+ description: "Total CPU seconds broken down by different states.");
}
- ///
- /// Initializes a new instance of the class.
- ///
- /// The options to define the metrics.
- public ProcessMetrics(ProcessInstrumentationOptions options)
+ private void Snapshot()
{
+ this.currentProcess.Refresh();
+ this.memoryUsage = this.currentProcess.WorkingSet64;
+ this.virtualMemoryUsage = this.currentProcess.PrivateMemorySize64;
+ this.userProcessorTime = this.currentProcess.UserProcessorTime.TotalSeconds;
+ this.privilegedProcessorTime = this.currentProcess.PrivilegedProcessorTime.TotalSeconds;
}
}
diff --git a/src/OpenTelemetry.Instrumentation.Runtime/README.md b/src/OpenTelemetry.Instrumentation.Runtime/README.md
index 4987f4ac91..f2b465b82e 100644
--- a/src/OpenTelemetry.Instrumentation.Runtime/README.md
+++ b/src/OpenTelemetry.Instrumentation.Runtime/README.md
@@ -96,9 +96,6 @@ to all the `ObservableGauge` below.
Note: This metric is only available when targeting .NET6 or later.
-Note: `gc.heap.fragmentation.size` metrics is removed for .NET 6 because of a
-[bug](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/issues/496).
-
| Units | Instrument Type | Value Type | Attribute Key(s) | Attribute Values |
|---------|-----------------|------------|------------------|------------------|
| `bytes` | ObservableGauge | `Int64` | No Attributes | N/A |
@@ -135,7 +132,7 @@ The API used to retrieve the value is:
The heap fragmentation, as observed during the latest garbage collection.
The value will be unavailable until at least one garbage collection has occurred.
-Note: This metric is only available when targeting .NET6 or later.
+Note: This metric is only available when targeting .NET 7 or later.
| Units | Instrument Type | Value Type | Attribute Key(s) | Attribute Values |
|---------|-----------------|------------|------------------|----------------------------|
diff --git a/test/OpenTelemetry.Exporter.Geneva.Benchmark/Exporter/LogExporterBenchmarks.cs b/test/OpenTelemetry.Exporter.Geneva.Benchmark/Exporter/LogExporterBenchmarks.cs
index 876d10f014..4c6c4bc122 100644
--- a/test/OpenTelemetry.Exporter.Geneva.Benchmark/Exporter/LogExporterBenchmarks.cs
+++ b/test/OpenTelemetry.Exporter.Geneva.Benchmark/Exporter/LogExporterBenchmarks.cs
@@ -20,42 +20,42 @@
using OpenTelemetry.Logs;
/*
-BenchmarkDotNet=v0.13.1, OS=Windows 10.0.22000
+BenchmarkDotNet=v0.13.1, OS=Windows 10.0.22621
Intel Core i7-9700 CPU 3.00GHz, 1 CPU, 8 logical and 8 physical cores
.NET SDK=7.0.100-preview.6.22352.1
- [Host] : .NET 6.0.8 (6.0.822.36306), X64 RyuJIT
- DefaultJob : .NET 6.0.8 (6.0.822.36306), X64 RyuJIT
+ [Host] : .NET 6.0.9 (6.0.922.41905), X64 RyuJIT
+ DefaultJob : .NET 6.0.9 (6.0.922.41905), X64 RyuJIT
Without Scopes
-| Method | IncludeFormattedMessage | Mean | Error | StdDev | Gen 0 | Allocated |
-|-------------------------- |------------------------ |---------:|---------:|---------:|-------:|----------:|
-| LoggerWithMessageTemplate | False | 979.5 ns | 11.46 ns | 10.72 ns | 0.0401 | 256 B |
-| LoggerWithDirectLoggerAPI | False | 887.9 ns | 17.24 ns | 16.13 ns | 0.0620 | 392 B |
-| LoggerWithSourceGenerator | False | 965.8 ns | 16.84 ns | 15.75 ns | 0.0343 | 216 B |
-| SerializeLogRecord | False | 696.5 ns | 13.94 ns | 14.92 ns | 0.0038 | 24 B |
-| Export | False | 744.9 ns | 12.91 ns | 12.08 ns | 0.0038 | 24 B |
-| LoggerWithMessageTemplate | True | 978.6 ns | 18.95 ns | 19.46 ns | 0.0401 | 256 B |
-| LoggerWithDirectLoggerAPI | True | 878.3 ns | 11.43 ns | 10.69 ns | 0.0620 | 392 B |
-| LoggerWithSourceGenerator | True | 942.8 ns | 14.55 ns | 13.61 ns | 0.0343 | 216 B |
-| SerializeLogRecord | True | 707.3 ns | 9.01 ns | 8.42 ns | 0.0038 | 24 B |
-| Export | True | 752.0 ns | 8.97 ns | 7.49 ns | 0.0038 | 24 B |
+| Method | IncludeFormattedMessage | Mean | Error | StdDev | Gen 0 | Allocated |
+|-------------------------- |------------------------ |-----------:|--------:|--------:|-------:|----------:|
+| LoggerWithMessageTemplate | False | 1,273.1 ns | 6.09 ns | 5.39 ns | 0.0362 | 232 B |
+| LoggerWithDirectLoggerAPI | False | 1,213.0 ns | 9.71 ns | 8.61 ns | 0.0572 | 368 B |
+| LoggerWithSourceGenerator | False | 1,243.5 ns | 6.13 ns | 5.44 ns | 0.0305 | 192 B |
+| SerializeLogRecord | False | 587.7 ns | 2.71 ns | 2.54 ns | - | - |
+| Export | False | 955.0 ns | 5.46 ns | 5.11 ns | - | - |
+| LoggerWithMessageTemplate | True | 1,261.1 ns | 6.59 ns | 5.84 ns | 0.0362 | 232 B |
+| LoggerWithDirectLoggerAPI | True | 1,214.4 ns | 4.56 ns | 4.27 ns | 0.0572 | 368 B |
+| LoggerWithSourceGenerator | True | 1,229.6 ns | 6.84 ns | 6.40 ns | 0.0305 | 192 B |
+| SerializeLogRecord | True | 581.6 ns | 2.38 ns | 2.11 ns | - | - |
+| Export | True | 958.4 ns | 3.02 ns | 2.52 ns | - | - |
With Scopes (https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/545)
-| Method | IncludeFormattedMessage | Mean | Error | StdDev | Median | Gen 0 | Allocated |
-|-------------------------- |------------------------ |-----------:|---------:|---------:|-----------:|-------:|----------:|
-| LoggerWithMessageTemplate | False | 1,042.8 ns | 19.34 ns | 54.55 ns | 1,022.1 ns | 0.0572 | 360 B |
-| LoggerWithDirectLoggerAPI | False | 953.4 ns | 13.90 ns | 13.00 ns | 950.4 ns | 0.0782 | 496 B |
-| LoggerWithSourceGenerator | False | 962.1 ns | 18.93 ns | 17.71 ns | 957.6 ns | 0.0496 | 320 B |
-| SerializeLogRecord | False | 722.8 ns | 6.26 ns | 5.23 ns | 722.9 ns | 0.0200 | 128 B |
-| Export | False | 789.2 ns | 15.11 ns | 14.14 ns | 787.3 ns | 0.0200 | 128 B |
-| LoggerWithMessageTemplate | True | 986.8 ns | 12.56 ns | 11.13 ns | 983.4 ns | 0.0572 | 360 B |
-| LoggerWithDirectLoggerAPI | True | 932.1 ns | 18.25 ns | 20.29 ns | 924.7 ns | 0.0782 | 496 B |
-| LoggerWithSourceGenerator | True | 980.0 ns | 15.56 ns | 14.55 ns | 979.6 ns | 0.0496 | 320 B |
-| SerializeLogRecord | True | 737.5 ns | 13.46 ns | 12.59 ns | 738.8 ns | 0.0200 | 128 B |
-| Export | True | 772.2 ns | 14.02 ns | 13.11 ns | 774.8 ns | 0.0200 | 128 B |
+| Method | IncludeFormattedMessage | Mean | Error | StdDev | Gen 0 | Allocated |
+|-------------------------- |------------------------ |-----------:|--------:|--------:|-------:|----------:|
+| LoggerWithMessageTemplate | False | 1,280.8 ns | 7.45 ns | 6.61 ns | 0.0534 | 336 B |
+| LoggerWithDirectLoggerAPI | False | 1,261.5 ns | 6.38 ns | 5.96 ns | 0.0744 | 472 B |
+| LoggerWithSourceGenerator | False | 1,309.3 ns | 4.83 ns | 4.52 ns | 0.0458 | 296 B |
+| SerializeLogRecord | False | 611.3 ns | 4.63 ns | 4.11 ns | 0.0162 | 104 B |
+| Export | False | 1,012.2 ns | 7.56 ns | 7.07 ns | 0.0153 | 104 B |
+| LoggerWithMessageTemplate | True | 1,278.3 ns | 6.63 ns | 5.88 ns | 0.0534 | 336 B |
+| LoggerWithDirectLoggerAPI | True | 1,263.8 ns | 8.26 ns | 7.73 ns | 0.0744 | 472 B |
+| LoggerWithSourceGenerator | True | 1,273.4 ns | 5.57 ns | 5.21 ns | 0.0458 | 296 B |
+| SerializeLogRecord | True | 604.3 ns | 2.83 ns | 2.65 ns | 0.0162 | 104 B |
+| Export | True | 1,003.6 ns | 9.29 ns | 8.69 ns | 0.0153 | 104 B |
*/
namespace OpenTelemetry.Exporter.Geneva.Benchmark;
@@ -65,7 +65,7 @@ public class LogExporterBenchmarks
{
private readonly ILogger logger;
private readonly ILoggerFactory loggerFactory;
- private readonly GenevaLogExporter exporter;
+ private readonly MsgPackLogExporter exporter;
private readonly LogRecord logRecord;
private readonly Batch batch;
@@ -97,7 +97,7 @@ public LogExporterBenchmarks()
// For msgpack serialization + export
this.logRecord = GenerateTestLogRecord();
this.batch = GenerateTestLogRecordBatch();
- this.exporter = new GenevaLogExporter(new GenevaExporterOptions
+ this.exporter = new MsgPackLogExporter(new GenevaExporterOptions
{
ConnectionString = "EtwSession=OpenTelemetry",
PrepopulatedFields = new Dictionary
diff --git a/test/OpenTelemetry.Exporter.Geneva.Benchmark/Exporter/TraceExporterBenchmarks.cs b/test/OpenTelemetry.Exporter.Geneva.Benchmark/Exporter/TraceExporterBenchmarks.cs
index 3460304ff1..3956343f72 100644
--- a/test/OpenTelemetry.Exporter.Geneva.Benchmark/Exporter/TraceExporterBenchmarks.cs
+++ b/test/OpenTelemetry.Exporter.Geneva.Benchmark/Exporter/TraceExporterBenchmarks.cs
@@ -14,23 +14,24 @@
// limitations under the License.
//
+using System;
using System.Collections.Generic;
using System.Diagnostics;
using BenchmarkDotNet.Attributes;
using OpenTelemetry.Trace;
/*
-BenchmarkDotNet=v0.13.1, OS=Windows 10.0.22000
+BenchmarkDotNet=v0.13.1, OS=Windows 10.0.22621
Intel Core i7-9700 CPU 3.00GHz, 1 CPU, 8 logical and 8 physical cores
.NET SDK=7.0.100-preview.6.22352.1
- [Host] : .NET 6.0.8 (6.0.822.36306), X64 RyuJIT
- DefaultJob : .NET 6.0.8 (6.0.822.36306), X64 RyuJIT
+ [Host] : .NET 6.0.9 (6.0.922.41905), X64 RyuJIT
+ DefaultJob : .NET 6.0.9 (6.0.922.41905), X64 RyuJIT
| Method | Mean | Error | StdDev | Gen 0 | Allocated |
|------------------ |---------:|--------:|--------:|-------:|----------:|
-| ExportActivity | 422.0 ns | 8.41 ns | 8.64 ns | 0.0062 | 40 B |
-| SerializeActivity | 387.4 ns | 7.22 ns | 7.09 ns | 0.0062 | 40 B |
+| ExportActivity | 719.9 ns | 5.83 ns | 5.45 ns | 0.0057 | 40 B |
+| SerializeActivity | 361.7 ns | 1.09 ns | 0.97 ns | 0.0062 | 40 B |
*/
namespace OpenTelemetry.Exporter.Geneva.Benchmark;
@@ -40,7 +41,7 @@ public class TraceExporterBenchmarks
{
private readonly Activity activity;
private readonly Batch batch;
- private readonly GenevaTraceExporter exporter;
+ private readonly MsgPackTraceExporter exporter;
private readonly ActivitySource activitySource = new ActivitySource("OpenTelemetry.Exporter.Geneva.Benchmark");
public TraceExporterBenchmarks()
@@ -67,7 +68,7 @@ public TraceExporterBenchmarks()
this.activity?.SetStatus(Status.Error);
}
- this.exporter = new GenevaTraceExporter(new GenevaExporterOptions
+ this.exporter = new MsgPackTraceExporter(new GenevaExporterOptions
{
ConnectionString = "EtwSession=OpenTelemetry",
PrepopulatedFields = new Dictionary
diff --git a/test/OpenTelemetry.Exporter.Geneva.Benchmark/OpenTelemetry.Exporter.Geneva.Benchmark.csproj b/test/OpenTelemetry.Exporter.Geneva.Benchmark/OpenTelemetry.Exporter.Geneva.Benchmark.csproj
index ca229c6b57..57236f7a96 100644
--- a/test/OpenTelemetry.Exporter.Geneva.Benchmark/OpenTelemetry.Exporter.Geneva.Benchmark.csproj
+++ b/test/OpenTelemetry.Exporter.Geneva.Benchmark/OpenTelemetry.Exporter.Geneva.Benchmark.csproj
@@ -8,7 +8,7 @@
-
+
diff --git a/test/OpenTelemetry.Exporter.Geneva.Tests/GenevaLogExporterTests.cs b/test/OpenTelemetry.Exporter.Geneva.Tests/GenevaLogExporterTests.cs
index d86edadca5..1014c7b2da 100644
--- a/test/OpenTelemetry.Exporter.Geneva.Tests/GenevaLogExporterTests.cs
+++ b/test/OpenTelemetry.Exporter.Geneva.Tests/GenevaLogExporterTests.cs
@@ -171,7 +171,7 @@ public void TableNameMappingTest(params string[] category)
.AddFilter("*", LogLevel.Trace)); // Enable all LogLevels
// Create a test exporter to get MessagePack byte data to validate if the data was serialized correctly.
- using var exporter = new GenevaLogExporter(exporterOptions);
+ using var exporter = new MsgPackLogExporter(exporterOptions);
ILogger logger;
ThreadLocal m_buffer;
@@ -188,7 +188,7 @@ public void TableNameMappingTest(params string[] category)
logger.LogError("this does not matter");
Assert.Single(logRecordList);
- m_buffer = typeof(GenevaLogExporter).GetField("m_buffer", BindingFlags.NonPublic | BindingFlags.Static).GetValue(exporter) as ThreadLocal;
+ m_buffer = typeof(MsgPackLogExporter).GetField("m_buffer", BindingFlags.NonPublic | BindingFlags.Static).GetValue(exporter) as ThreadLocal;
_ = exporter.SerializeLogRecord(logRecordList[0]);
fluentdData = MessagePack.MessagePackSerializer.Deserialize