(options: StartSpanOptions, callback: (span: Span, finish: () => void) => T)
| 114 | * it may just be a non-recording span if the span is not sampled or if tracing is disabled. |
| 115 | */ |
| 116 | export function startSpanManual<T>(options: StartSpanOptions, callback: (span: Span, finish: () => void) => T): T { |
| 117 | const acs = getAcs(); |
| 118 | if (acs.startSpanManual) { |
| 119 | return acs.startSpanManual(options, callback); |
| 120 | } |
| 121 | |
| 122 | const spanArguments = parseSentrySpanArguments(options); |
| 123 | const { forceTransaction, parentSpan: customParentSpan, scope: customScope } = options; |
| 124 | |
| 125 | const customForkedScope = customScope?.clone(); |
| 126 | |
| 127 | return withScope(customForkedScope, () => { |
| 128 | // If `options.parentSpan` is defined, we want to wrap the callback in `withActiveSpan` |
| 129 | const wrapper = getActiveSpanWrapper<T>(customParentSpan); |
| 130 | |
| 131 | return wrapper(() => { |
| 132 | const scope = getCurrentScope(); |
| 133 | const parentSpan = getParentSpan(scope, customParentSpan); |
| 134 | |
| 135 | const missingRequiredParent = options.onlyIfParent && !parentSpan; |
| 136 | const activeSpan = missingRequiredParent |
| 137 | ? startMissingRequiredParentSpan(scope, getClient()) |
| 138 | : createChildOrRootSpan({ |
| 139 | parentSpan, |
| 140 | spanArguments, |
| 141 | forceTransaction, |
| 142 | scope, |
| 143 | }); |
| 144 | |
| 145 | // We don't set ignored child spans onto the scope because there likely is an active, |
| 146 | // unignored span on the scope already. |
| 147 | if (!_isIgnoredSpan(activeSpan) || !parentSpan) { |
| 148 | _setSpanForScope(scope, activeSpan); |
| 149 | } |
| 150 | |
| 151 | return handleCallbackErrors( |
| 152 | // We pass the `finish` function to the callback, so the user can finish the span manually |
| 153 | // this is mainly here for historic purposes because previously, we instructed users to call |
| 154 | // `finish` instead of `span.end()` to also clean up the scope. Nowadays, calling `span.end()` |
| 155 | // or `finish` has the same effect and we simply leave it here to avoid breaking user code. |
| 156 | () => callback(activeSpan, () => activeSpan.end()), |
| 157 | () => { |
| 158 | // Only update the span status if it hasn't been changed yet, and the span is not yet finished |
| 159 | const { status } = spanToJSON(activeSpan); |
| 160 | if (activeSpan.isRecording() && (!status || status === 'ok')) { |
| 161 | activeSpan.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' }); |
| 162 | } |
| 163 | }, |
| 164 | ); |
| 165 | }); |
| 166 | }); |
| 167 | } |
| 168 | |
| 169 | /** |
| 170 | * Creates a span. This span is not set as active, so will not get automatic instrumentation spans |
no test coverage detected