@@ -44,6 +44,16 @@ interface AwsV3Command {
4444 constructor ?: { name ?: string } ;
4545}
4646
47+ /** Runs a span-building callback so a throw inside it can never break the user's aws-sdk call. */
48+ function safe < T > ( fn : ( ) => T ) : T | undefined {
49+ try {
50+ return fn ( ) ;
51+ } catch ( error ) {
52+ DEBUG_BUILD && debug . warn ( '[orchestrion:aws-sdk] error building span' , error ) ;
53+ return undefined ;
54+ }
55+ }
56+
4757// `metadata` is smithy's `ResponseMetadata`, read off the untyped channel result/error (`any` for the
4858// same reason as `CommandInput`, see types.ts).
4959function setMetadataAttributes ( span : Span , metadata : Record < string , any > | undefined ) : void {
@@ -73,10 +83,8 @@ const _awsChannelIntegration = (() => {
7383 return ;
7484 }
7585
76- // Everything in here (and in `deferSpanEnd` below) runs inside the tracingChannel machinery
77- // wrapping the user's `send` call, so a throw must never escape: it would break the AWS call.
78- const getSpan = ( data : AwsSendChannelContext ) : Span | undefined => {
79- try {
86+ const getSpan = ( data : AwsSendChannelContext ) : Span | undefined =>
87+ safe ( ( ) => {
8088 const command = data . arguments [ 0 ] as AwsV3Command | undefined ;
8189 const commandName = command ?. constructor ?. name ;
8290 if ( ! command || ! commandName ) {
@@ -125,7 +133,7 @@ const _awsChannelIntegration = (() => {
125133 // so `cloud.region` cannot be lost when `send` settles first (e.g. an early failure).
126134 //
127135 // The provider call is guarded separately: the span is already started, so a synchronous
128- // throw bubbling into the enclosing catch would discard it without ending it (a leaked
136+ // throw bubbling into the enclosing `safe` would discard it without ending it (a leaked
129137 // open span).
130138 let regionResult : string | Promise < string > | undefined ;
131139 try {
@@ -153,20 +161,11 @@ const _awsChannelIntegration = (() => {
153161 data . _sentryRegion = regionHolder ;
154162
155163 // Inject trace-propagation headers into outgoing messages (SQS/SNS/Lambda). Runs before
156- // `send` proceeds, so the mutated `commandInput` is used to build the request. Guarded
157- // separately so a throw can't discard the already-started span via the outer catch.
158- try {
159- servicesExtensions . requestPostSpanHook ( normalizedRequest , span ) ;
160- } catch ( error ) {
161- DEBUG_BUILD && debug . warn ( '[orchestrion:aws-sdk] error in request post-span hook' , error ) ;
162- }
164+ // `send` proceeds, so the mutated `commandInput` is used to build the request.
165+ safe ( ( ) => servicesExtensions . requestPostSpanHook ( normalizedRequest , span ) ) ;
163166
164167 return span ;
165- } catch ( error ) {
166- DEBUG_BUILD && debug . warn ( '[orchestrion:aws-sdk] error building span' , error ) ;
167- return undefined ;
168- }
169- } ;
168+ } ) ;
170169
171170 const opts : TracingChannelLifeCycleOptions < AwsSendChannelContext > = {
172171 deferSpanEnd ( { span, data, end } ) {
@@ -179,9 +178,8 @@ const _awsChannelIntegration = (() => {
179178 const failed = 'error' in data ;
180179
181180 // The channel `result`/`error` are untyped; the `$metadata` casts below name smithy's
182- // `ResponseMetadata` shape (`any`-valued, see `setMetadataAttributes`). Guarded so an
183- // enrichment throw can't escape into the user's `send` (see `getSpan`).
184- try {
181+ // `ResponseMetadata` shape (`any`-valued, see `setMetadataAttributes`).
182+ safe ( ( ) => {
185183 if ( failed ) {
186184 const err = data . error as
187185 | { $metadata ?: Record < string , any > ; RequestId ?: string ; extendedRequestId ?: string }
@@ -195,20 +193,19 @@ const _awsChannelIntegration = (() => {
195193 httpStatusCode : errMetadata ?. httpStatusCode ,
196194 extendedRequestId : err ?. extendedRequestId ?? errMetadata ?. extendedRequestId ,
197195 } ) ;
198- } else {
199- const output = data . result as { $metadata ?: Record < string , any > } | undefined ;
200- setMetadataAttributes ( span , output ?. $metadata ) ;
201-
202- const normalizedResponse : NormalizedResponse = {
203- data : output ,
204- request : normalizedRequest ,
205- requestId : output ?. $metadata ?. requestId ,
206- } ;
207- servicesExtensions . responseHook ( normalizedResponse , span ) ;
196+ return ;
208197 }
209- } catch ( error ) {
210- DEBUG_BUILD && debug . warn ( '[orchestrion:aws-sdk] error enriching span' , error ) ;
211- }
198+
199+ const output = data . result as { $metadata ?: Record < string , any > } | undefined ;
200+ setMetadataAttributes ( span , output ?. $metadata ) ;
201+
202+ const normalizedResponse : NormalizedResponse = {
203+ data : output ,
204+ request : normalizedRequest ,
205+ requestId : output ?. $metadata ?. requestId ,
206+ } ;
207+ servicesExtensions . responseHook ( normalizedResponse , span ) ;
208+ } ) ;
212209
213210 // Streaming responses end the span when their wrapped stream is consumed (see
214211 // bedrock-runtime); the helper must not end it on `send` settling. Errors always end here.
0 commit comments