@@ -41,7 +41,8 @@ import {
4141 traceAttempt ,
4242 ResendRecorder ,
4343} from './observability/TracerHelper' ;
44- import { checkTracingEnabled } from './observability/util' ;
44+ import { logCall , logNetworkAttempt } from './observability/LoggerHelper' ;
45+ import { checkLoggingEnabled , checkTracingEnabled } from './observability/util' ;
4546import {
4647 StaticTraceContext ,
4748 DynamicTraceContext ,
@@ -84,21 +85,24 @@ export function createApiCall(
8485 const apiCaller = createAPICaller ( settings , descriptor ) ;
8586
8687 const tracingEnabled = checkTracingEnabled ( settings ) ;
87- const staticArgs : StaticTraceContext | undefined = tracingEnabled
88- ? resolveStaticTraceContext ( settings )
89- : undefined ;
88+ const loggingEnabled = checkLoggingEnabled ( settings ) ;
89+ const staticArgs : StaticTraceContext | undefined =
90+ tracingEnabled || loggingEnabled
91+ ? resolveStaticTraceContext ( settings )
92+ : undefined ;
9093 const serviceName = settings . apiName ?. split ( '.' ) . pop ( ) ?? '' ;
9194 const isFallback = Boolean ( _fallback ) ;
92- const dynamicArgs : DynamicTraceContext | undefined = tracingEnabled
93- ? {
94- clientName : serviceName ? `${ serviceName } Client` : '' ,
95- methodName : settings . otherArgs ?. internalMethodName ?? '' ,
96- rpcType : isFallback ? 'http' : 'grpc' ,
97- }
98- : undefined ;
95+ const dynamicArgs : DynamicTraceContext | undefined =
96+ tracingEnabled || loggingEnabled
97+ ? {
98+ clientName : serviceName ? `${ serviceName } Client` : '' ,
99+ methodName : settings . otherArgs ?. internalMethodName ?? '' ,
100+ rpcType : isFallback ? 'http' : 'grpc' ,
101+ }
102+ : undefined ;
99103 // Context for per-attempt low level network CLIENT spans.
100104 const attemptDynamicArgs : AttemptTraceContext | undefined =
101- tracingEnabled && dynamicArgs
105+ ( tracingEnabled || loggingEnabled ) && dynamicArgs
102106 ? {
103107 ...dynamicArgs ,
104108 apiName : settings . apiName ?? '' ,
@@ -163,33 +167,60 @@ export function createApiCall(
163167 ?. streaming ;
164168
165169 // Wrap the transport call so each attempt (initial send and retries) emits a low level network CLIENT span.
166- if ( tracingEnabled && attemptDynamicArgs && staticArgs ) {
170+ if (
171+ ( tracingEnabled || loggingEnabled ) &&
172+ attemptDynamicArgs &&
173+ staticArgs
174+ ) {
167175 const callerWrappedFunc = wrappedFunc ;
168176 wrappedFunc = (
169177 argument : { } ,
170178 metadata : { } ,
171179 options : { } ,
172180 attemptCallback : APICallback ,
173181 ) : GRPCCallResult => {
174- if ( ! isRetryAttempt ) {
175- attemptResendCount = 0 ;
182+ let attemptExecution = ( cb : APICallback ) : GRPCCallResult =>
183+ Reflect . apply ( callerWrappedFunc , undefined , [
184+ argument ,
185+ metadata ,
186+ options ,
187+ cb ,
188+ ] ) ;
189+
190+ // If logging is enabled, wrap with L4 attempt error logging
191+ if ( loggingEnabled ) {
192+ const originalAttemptExecution = attemptExecution ;
193+ attemptExecution = ( cb : APICallback ) =>
194+ logNetworkAttempt (
195+ attemptDynamicArgs ,
196+ staticArgs ,
197+ loggedCallback =>
198+ originalAttemptExecution ( loggedCallback ?? cb ) ,
199+ Boolean ( streaming ) ,
200+ cb ,
201+ ) ;
176202 }
177- isRetryAttempt = false ;
178- const resendCount = attemptResendCount ;
179- return traceAttempt (
180- { ...attemptDynamicArgs , resendCount} ,
181- staticArgs ,
182- tracedAttemptCallback =>
183- Reflect . apply ( callerWrappedFunc , undefined , [
184- argument ,
185- metadata ,
186- options ,
187- tracedAttemptCallback ?? attemptCallback ,
188- ] ) ,
189- Boolean ( streaming ) ,
190- attemptCallback ,
191- parentContext ,
192- ) ;
203+
204+ if ( tracingEnabled ) {
205+ if ( ! isRetryAttempt ) {
206+ attemptResendCount = 0 ;
207+ }
208+ isRetryAttempt = false ;
209+ const resendCount = attemptResendCount ;
210+ const originalAttemptExecution = attemptExecution ;
211+ attemptExecution = ( cb : APICallback ) =>
212+ traceAttempt (
213+ { ...attemptDynamicArgs , resendCount} ,
214+ staticArgs ,
215+ tracedAttemptCallback =>
216+ originalAttemptExecution ( tracedAttemptCallback ?? cb ) ,
217+ Boolean ( streaming ) ,
218+ cb ,
219+ parentContext ,
220+ ) ;
221+ }
222+
223+ return attemptExecution ( attemptCallback ) ;
193224 } ;
194225 }
195226
@@ -261,27 +292,54 @@ export function createApiCall(
261292 return currentApiCaller . result ( ongoingCall ) ;
262293 } ;
263294
264- if ( tracingEnabled && dynamicArgs && staticArgs ) {
295+ if (
296+ ( tracingEnabled || loggingEnabled ) &&
297+ dynamicArgs &&
298+ attemptDynamicArgs &&
299+ staticArgs
300+ ) {
265301 const isStreamingCall = apiCaller instanceof StreamingApiCaller ;
266302 return (
267303 request : RequestType ,
268304 callOptions ?: CallOptions ,
269305 callback ?: APICallback ,
270306 ) => {
271- return traceCall (
272- dynamicArgs ,
273- staticArgs ,
274- ( tracedCallback ?: APICallback ) => {
275- // `traceCall` wraps the user's callback whenever one was supplied,
276- // for stream and non-stream calls alike, and that wrapper is what
277- // closes the span. It is undefined only when there is no callback to
278- // wrap, in which case the span is bound to the returned promise or
279- // stream instead; the fallback keeps this correct either way.
280- return invokeCall ( request , callOptions , tracedCallback ?? callback ) ;
281- } ,
282- isStreamingCall ,
283- callback ,
284- ) ;
307+ let callExecution = ( cb ?: APICallback ) =>
308+ invokeCall ( request , callOptions , cb ) ;
309+
310+ // Wrap with L3 terminal logging
311+ if ( loggingEnabled ) {
312+ const originalCallExecution = callExecution ;
313+ callExecution = ( cb ?: APICallback ) =>
314+ logCall (
315+ attemptDynamicArgs ,
316+ staticArgs ,
317+ loggedCallback => originalCallExecution ( loggedCallback ?? cb ) ,
318+ isStreamingCall ,
319+ cb ,
320+ ) ;
321+ }
322+
323+ if ( tracingEnabled ) {
324+ const originalCallExecution = callExecution ;
325+ callExecution = ( cb ?: APICallback ) =>
326+ traceCall (
327+ dynamicArgs ,
328+ staticArgs ,
329+ ( tracedCallback ?: APICallback ) => {
330+ // `traceCall` wraps the user's callback whenever one was supplied,
331+ // for stream and non-stream calls alike, and that wrapper is what
332+ // closes the span. It is undefined only when there is no callback to
333+ // wrap, in which case the span is bound to the returned promise or
334+ // stream instead; the fallback keeps this correct either way.
335+ return originalCallExecution ( tracedCallback ?? cb ) ;
336+ } ,
337+ isStreamingCall ,
338+ cb ,
339+ ) ;
340+ }
341+
342+ return callExecution ( callback ) ;
285343 } ;
286344 } else {
287345 return invokeCall ;
0 commit comments