diff --git a/src/OpenTelemetry.Exporter.Geneva/.publicApi/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Exporter.Geneva/.publicApi/PublicAPI.Unshipped.txt
index e69de29bb2..44dadc78df 100644
--- a/src/OpenTelemetry.Exporter.Geneva/.publicApi/PublicAPI.Unshipped.txt
+++ b/src/OpenTelemetry.Exporter.Geneva/.publicApi/PublicAPI.Unshipped.txt
@@ -0,0 +1 @@
+OpenTelemetry.Exporter.Geneva.ExceptionStackExportMode.ExportAsStackTraceString = 2 -> OpenTelemetry.Exporter.Geneva.ExceptionStackExportMode
\ No newline at end of file
diff --git a/src/OpenTelemetry.Exporter.Geneva/CHANGELOG.md b/src/OpenTelemetry.Exporter.Geneva/CHANGELOG.md
index 5635ffc0c0..3fc87b0de5 100644
--- a/src/OpenTelemetry.Exporter.Geneva/CHANGELOG.md
+++ b/src/OpenTelemetry.Exporter.Geneva/CHANGELOG.md
@@ -2,6 +2,12 @@
## Unreleased
+* Added support for exporting exception stack traces using
+ `Exception.StackTrace`. This can be enabled via the
+ `ExceptionStackExportMode.ExportAsStackTraceString` enum. Applicable only to
+ the LogExporter.
+ ([#2422](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/2422))
+
## 1.10.0
Released 2024-Nov-18
diff --git a/src/OpenTelemetry.Exporter.Geneva/ExceptionStackExportMode.cs b/src/OpenTelemetry.Exporter.Geneva/ExceptionStackExportMode.cs
index 9030a32b9c..87b2ec20ae 100644
--- a/src/OpenTelemetry.Exporter.Geneva/ExceptionStackExportMode.cs
+++ b/src/OpenTelemetry.Exporter.Geneva/ExceptionStackExportMode.cs
@@ -4,19 +4,36 @@
namespace OpenTelemetry.Exporter.Geneva;
///
-/// Contains the exception stack trace export mode defintions.
+/// Defines modes for exporting exception stack traces. Currently applicable only to the Logs signal.
///
public enum ExceptionStackExportMode
{
///
- /// Exception stack traces are dropped.
+ /// Exception stack traces are dropped and not exported.
///
Drop,
///
- /// Exception stack traces are exported as strings.
+ /// Exports exception stack traces as a string using the ToString() implementation of the exception.
+ /// The output is formatted in a culture-agnostic manner and is primarily designed for human readability.
+ /// See .
///
+ ///
+ /// Typically, ToString() includes information about inner exceptions and additional details,
+ /// such as the exception message. However, this behavior is not guaranteed, as custom exceptions
+ /// can override ToString() to return arbitrary content.
+ ///
ExportAsString,
+ ///
+ /// Exports exception stack traces as a string using the StackTrace property of the exception.
+ /// See .
+ ///
+ ///
+ /// This represents the raw stack trace and does not include inner exception details.
+ /// Note that the StackTrace property can also be overridden in custom exception implementations.
+ ///
+ ExportAsStackTraceString,
+
// ExportAsArrayOfStacks - future if stacks can be exported in more structured way
}
diff --git a/src/OpenTelemetry.Exporter.Geneva/Internal/MsgPack/MsgPackLogExporter.cs b/src/OpenTelemetry.Exporter.Geneva/Internal/MsgPack/MsgPackLogExporter.cs
index de39f6e7fd..ba3c9969c1 100644
--- a/src/OpenTelemetry.Exporter.Geneva/Internal/MsgPack/MsgPackLogExporter.cs
+++ b/src/OpenTelemetry.Exporter.Geneva/Internal/MsgPack/MsgPackLogExporter.cs
@@ -419,20 +419,30 @@ internal ArraySegment SerializeLogRecord(LogRecord logRecord)
cursor = MessagePackSerializer.SerializeUnicodeString(buffer, cursor, logRecord.Exception.Message);
cntFields += 1;
+ // The current approach relies on the existing trim
+ // capabilities which trims string in excess of STRING_SIZE_LIMIT_CHAR_COUNT
+ // TODO: Revisit this:
+ // 1. Trim it off based on how much more bytes are available
+ // before running out of limit instead of STRING_SIZE_LIMIT_CHAR_COUNT.
+ // 2. Trim smarter, by trimming the middle of stack, an
+ // keep top and bottom.
if (this.exportExceptionStack == ExceptionStackExportMode.ExportAsString)
{
- // The current approach relies on the existing trim
- // capabilities which trims string in excess of STRING_SIZE_LIMIT_CHAR_COUNT
- // TODO: Revisit this:
- // 1. Trim it off based on how much more bytes are available
- // before running out of limit instead of STRING_SIZE_LIMIT_CHAR_COUNT.
- // 2. Trim smarter, by trimming the middle of stack, an
- // keep top and bottom.
var exceptionStack = logRecord.Exception.ToInvariantString();
cursor = MessagePackSerializer.SerializeAsciiString(buffer, cursor, "env_ex_stack");
cursor = MessagePackSerializer.SerializeUnicodeString(buffer, cursor, exceptionStack);
cntFields += 1;
}
+ else if (this.exportExceptionStack == ExceptionStackExportMode.ExportAsStackTraceString)
+ {
+ var exceptionStack = logRecord.Exception.StackTrace;
+ if (exceptionStack != null)
+ {
+ cursor = MessagePackSerializer.SerializeAsciiString(buffer, cursor, "env_ex_stack");
+ cursor = MessagePackSerializer.SerializeUnicodeString(buffer, cursor, exceptionStack);
+ cntFields += 1;
+ }
+ }
}
MessagePackSerializer.WriteUInt16(buffer, idxMapSizePatch, cntFields);
diff --git a/src/OpenTelemetry.Exporter.Geneva/Internal/Tld/TldLogExporter.cs b/src/OpenTelemetry.Exporter.Geneva/Internal/Tld/TldLogExporter.cs
index 1e28710271..9f31da3f01 100644
--- a/src/OpenTelemetry.Exporter.Geneva/Internal/Tld/TldLogExporter.cs
+++ b/src/OpenTelemetry.Exporter.Geneva/Internal/Tld/TldLogExporter.cs
@@ -260,6 +260,15 @@ internal EventBuilder SerializeLogRecord(LogRecord logRecord)
eb.AddCountedAnsiString("ext_ex_stack", exceptionStack, Encoding.UTF8, 0, Math.Min(exceptionStack.Length, StringLengthLimit));
partAFieldsCount++;
}
+ else if (this.exceptionStackExportMode == ExceptionStackExportMode.ExportAsStackTraceString)
+ {
+ var stackTrace = logRecord.Exception.StackTrace;
+ if (stackTrace != null)
+ {
+ eb.AddCountedAnsiString("ext_ex_stack", stackTrace, Encoding.UTF8, 0, Math.Min(stackTrace.Length, StringLengthLimit));
+ partAFieldsCount++;
+ }
+ }
}
eb.SetStructFieldCount(partAFieldsCountPatch, partAFieldsCount);