55
66package io .opentelemetry .instrumentation .openai .v1_1 ;
77
8+ import static io .opentelemetry .instrumentation .api .internal .SemconvExceptionSignal .emitExceptionAsLogs ;
9+ import static io .opentelemetry .instrumentation .api .internal .SemconvExceptionSignal .emitExceptionAsSpanEvents ;
810import static io .opentelemetry .sdk .testing .assertj .OpenTelemetryAssertions .equalTo ;
911import static io .opentelemetry .sdk .testing .assertj .OpenTelemetryAssertions .satisfies ;
12+ import static io .opentelemetry .semconv .ExceptionAttributes .EXCEPTION_MESSAGE ;
13+ import static io .opentelemetry .semconv .ExceptionAttributes .EXCEPTION_STACKTRACE ;
14+ import static io .opentelemetry .semconv .ExceptionAttributes .EXCEPTION_TYPE ;
1015import static io .opentelemetry .semconv .incubating .GenAiIncubatingAttributes .GEN_AI_OPERATION_NAME ;
1116import static io .opentelemetry .semconv .incubating .GenAiIncubatingAttributes .GEN_AI_PROVIDER_NAME ;
1217import static io .opentelemetry .semconv .incubating .GenAiIncubatingAttributes .GEN_AI_REQUEST_FREQUENCY_PENALTY ;
6166import io .opentelemetry .api .common .AttributeKey ;
6267import io .opentelemetry .api .common .KeyValue ;
6368import io .opentelemetry .api .common .Value ;
69+ import io .opentelemetry .api .logs .Severity ;
6470import io .opentelemetry .api .trace .Span ;
6571import io .opentelemetry .api .trace .SpanContext ;
6672import io .opentelemetry .context .Context ;
@@ -902,7 +908,7 @@ void connectionError() {
902908 trace .hasSpansSatisfyingExactly (
903909 maybeWithTransportSpan (
904910 span ->
905- span .hasException (thrown )
911+ span .hasException (emitExceptionAsSpanEvents () ? thrown : null )
906912 .hasAttributesSatisfyingExactly (
907913 equalTo (GEN_AI_PROVIDER_NAME , OPENAI ),
908914 equalTo (GEN_AI_OPERATION_NAME , CHAT ),
@@ -927,14 +933,33 @@ void connectionError() {
927933
928934 SpanContext spanCtx = getTesting ().waitForTraces (1 ).get (0 ).get (0 ).getSpanContext ();
929935
930- getTesting ()
931- .waitAndAssertLogRecords (
932- log ->
933- log .hasAttributesSatisfyingExactly (
934- equalTo (GEN_AI_PROVIDER_NAME , OPENAI ),
935- equalTo (EVENT_NAME , "gen_ai.user.message" ))
936- .hasSpanContext (spanCtx )
937- .hasBody (Value .of (KeyValue .of ("content" , Value .of (TEST_CHAT_INPUT )))));
936+ if (emitExceptionAsLogs ()) {
937+ getTesting ()
938+ .waitAndAssertLogRecords (
939+ log ->
940+ log .hasAttributesSatisfyingExactly (
941+ equalTo (GEN_AI_PROVIDER_NAME , OPENAI ),
942+ equalTo (EVENT_NAME , "gen_ai.user.message" ))
943+ .hasSpanContext (spanCtx )
944+ .hasBody (Value .of (KeyValue .of ("content" , Value .of (TEST_CHAT_INPUT )))),
945+ log ->
946+ log .hasSpanContext (spanCtx )
947+ .hasSeverity (Severity .WARN )
948+ .hasEventName ("gen_ai.client.operation.exception" )
949+ .hasAttributesSatisfyingExactly (
950+ equalTo (EXCEPTION_TYPE , thrown .getClass ().getName ()),
951+ equalTo (EXCEPTION_MESSAGE , thrown .getMessage ()),
952+ satisfies (EXCEPTION_STACKTRACE , val -> val .isNotNull ())));
953+ } else {
954+ getTesting ()
955+ .waitAndAssertLogRecords (
956+ log ->
957+ log .hasAttributesSatisfyingExactly (
958+ equalTo (GEN_AI_PROVIDER_NAME , OPENAI ),
959+ equalTo (EVENT_NAME , "gen_ai.user.message" ))
960+ .hasSpanContext (spanCtx )
961+ .hasBody (Value .of (KeyValue .of ("content" , Value .of (TEST_CHAT_INPUT )))));
962+ }
938963 }
939964
940965 @ Test
@@ -1609,7 +1634,7 @@ void streamConnectionError() {
16091634 trace .hasSpansSatisfyingExactly (
16101635 maybeWithTransportSpan (
16111636 span ->
1612- span .hasException (thrown )
1637+ span .hasException (emitExceptionAsSpanEvents () ? thrown : null )
16131638 .hasAttributesSatisfyingExactly (
16141639 equalTo (GEN_AI_PROVIDER_NAME , OPENAI ),
16151640 equalTo (GEN_AI_OPERATION_NAME , CHAT ),
@@ -1634,14 +1659,33 @@ void streamConnectionError() {
16341659
16351660 SpanContext spanCtx = getTesting ().waitForTraces (1 ).get (0 ).get (0 ).getSpanContext ();
16361661
1637- getTesting ()
1638- .waitAndAssertLogRecords (
1639- log ->
1640- log .hasAttributesSatisfyingExactly (
1641- equalTo (GEN_AI_PROVIDER_NAME , OPENAI ),
1642- equalTo (EVENT_NAME , "gen_ai.user.message" ))
1643- .hasSpanContext (spanCtx )
1644- .hasBody (Value .of (KeyValue .of ("content" , Value .of (TEST_CHAT_INPUT )))));
1662+ if (emitExceptionAsLogs ()) {
1663+ getTesting ()
1664+ .waitAndAssertLogRecords (
1665+ log ->
1666+ log .hasAttributesSatisfyingExactly (
1667+ equalTo (GEN_AI_PROVIDER_NAME , OPENAI ),
1668+ equalTo (EVENT_NAME , "gen_ai.user.message" ))
1669+ .hasSpanContext (spanCtx )
1670+ .hasBody (Value .of (KeyValue .of ("content" , Value .of (TEST_CHAT_INPUT )))),
1671+ log ->
1672+ log .hasSpanContext (spanCtx )
1673+ .hasSeverity (Severity .WARN )
1674+ .hasEventName ("gen_ai.client.operation.exception" )
1675+ .hasAttributesSatisfyingExactly (
1676+ equalTo (EXCEPTION_TYPE , thrown .getClass ().getName ()),
1677+ equalTo (EXCEPTION_MESSAGE , thrown .getMessage ()),
1678+ satisfies (EXCEPTION_STACKTRACE , val -> val .isNotNull ())));
1679+ } else {
1680+ getTesting ()
1681+ .waitAndAssertLogRecords (
1682+ log ->
1683+ log .hasAttributesSatisfyingExactly (
1684+ equalTo (GEN_AI_PROVIDER_NAME , OPENAI ),
1685+ equalTo (EVENT_NAME , "gen_ai.user.message" ))
1686+ .hasSpanContext (spanCtx )
1687+ .hasBody (Value .of (KeyValue .of ("content" , Value .of (TEST_CHAT_INPUT )))));
1688+ }
16451689 }
16461690
16471691 protected static ChatCompletionMessageParam createUserMessage (String content ) {
0 commit comments