-
Notifications
You must be signed in to change notification settings - Fork 37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Telemetry collection p2 #222
Changes from 9 commits
8964ea8
895c7ad
96fcb8a
30b0096
2e63bfd
86f3ab9
cc3f3bd
ceb214f
452c110
ba461cf
25cff64
912d826
aaf6f82
1e9b41f
d6e8202
c2a4ba5
852a2ce
f37dd25
8300b18
86bc460
50ec17a
6eb4e39
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -77,6 +77,13 @@ interface CommunicatorInfo { | |
config: CommunicatorConfig; | ||
} | ||
|
||
export const OperationType = { | ||
HANDLER: "handler", | ||
WORKFLOW: "workflow", | ||
TRANSACTION: "transaction", | ||
COMMUNICATOR: "communicator", | ||
} as const; | ||
Comment on lines
+80
to
+85
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Useful as span metadata |
||
|
||
const TempWorkflowType = { | ||
transaction: "transaction", | ||
external: "external", | ||
|
@@ -276,7 +283,7 @@ export class DBOSExecutor { | |
} catch (err) { | ||
(err as Error).message = `failed to initialize workflow executor: ${(err as Error).message}` | ||
this.logger.error(err); | ||
throw new DBOSInitializationError(`failed to initialize workflow executor: ${(err as Error).message}`); | ||
throw new DBOSInitializationError(`${(err as Error).message}`); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove duplicate text in this error message. |
||
} | ||
this.initialized = true; | ||
|
||
|
@@ -364,12 +371,8 @@ export class DBOSExecutor { | |
const wConfig = wInfo.config; | ||
|
||
const wCtxt: WorkflowContextImpl = new WorkflowContextImpl(this, params.parentCtx, workflowUUID, wConfig, wf.name, presetUUID); | ||
wCtxt.span.setAttributes({ args: JSON.stringify(args) }); // TODO enforce skipLogging & request for hashing | ||
|
||
let executorID: string = "local"; | ||
if (wCtxt.request.headers && wCtxt.request.headers[DBOSExecutorIDHeader]) { | ||
executorID = wCtxt.request.headers[DBOSExecutorIDHeader] as string; | ||
} | ||
wCtxt.span.setAttribute("executorID", wCtxt.executorID); | ||
const internalStatus: WorkflowStatusInternal = { | ||
workflowUUID: workflowUUID, | ||
status: StatusString.PENDING, | ||
|
@@ -380,7 +383,7 @@ export class DBOSExecutor { | |
assumedRole: wCtxt.assumedRole, | ||
authenticatedRoles: wCtxt.authenticatedRoles, | ||
request: wCtxt.request, | ||
executorID: executorID, | ||
executorID: wCtxt.executorID, | ||
}; | ||
// Synchronously set the workflow's status to PENDING and record workflow inputs. | ||
if (!wCtxt.isTempWorkflow) { | ||
|
@@ -638,10 +641,17 @@ export class DBOSExecutor { | |
} | ||
|
||
#getRecoveryContext(workflowUUID: string, status: WorkflowStatus): DBOSContextImpl { | ||
const span = this.tracer.startSpan(status.workflowName); | ||
span.setAttributes({ | ||
operationName: status.workflowName, | ||
}); | ||
const span = this.tracer.startSpan( | ||
status.workflowName, | ||
{ | ||
operationUUID: workflowUUID, | ||
operationType: OperationType.WORKFLOW, | ||
status: status.status, | ||
authenticatedUser: status.authenticatedUser, | ||
assumedRole: status.assumedRole, | ||
authenticatedRoles: status.authenticatedRoles, | ||
}, | ||
); | ||
const oc = new DBOSContextImpl(status.workflowName, span, this.logger); | ||
oc.request = status.request; | ||
oc.authenticatedUser = status.authenticatedUser; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
/* eslint-disable @typescript-eslint/no-explicit-any */ | ||
import { DBOSExecutor, DBOSNull, dbosNull } from "../dbos-executor"; | ||
import { DBOSExecutor, DBOSNull, OperationType, dbosNull } from "../dbos-executor"; | ||
import { transaction_outputs } from "../../schemas/user_db_schema"; | ||
import { Transaction, TransactionContextImpl } from "../transaction"; | ||
import { Communicator } from "../communicator"; | ||
|
@@ -27,7 +27,17 @@ export class WorkflowContextDebug extends DBOSContextImpl implements WorkflowCon | |
readonly isTempWorkflow: boolean; | ||
|
||
constructor(dbosExec: DBOSExecutor, parentCtx: DBOSContextImpl | undefined, workflowUUID: string, readonly workflowConfig: WorkflowConfig, workflowName: string) { | ||
const span = dbosExec.tracer.startSpan(workflowName, { workflowUUID: workflowUUID }, parentCtx?.span); | ||
const span = dbosExec.tracer.startSpan( | ||
workflowName, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why are we doing any sort of tracing in debug workflows? @qianl15 what do you think? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah right now the usage is unclear. Maybe we could need it for retro action, in the future. Happy to remove it if @qianl15 doesn't find it useful. |
||
{ | ||
operationUUID: workflowUUID, | ||
operationType: OperationType.WORKFLOW, | ||
authenticatedUser: parentCtx?.authenticatedUser ?? "", | ||
authenticatedRoles: parentCtx?.authenticatedRoles ?? [], | ||
assumedRole: parentCtx?.assumedRole ?? "", | ||
}, | ||
parentCtx?.span, | ||
); | ||
super(workflowName, span, dbosExec.logger, parentCtx); | ||
this.workflowUUID = workflowUUID; | ||
this.#dbosExec = dbosExec; | ||
|
@@ -98,7 +108,19 @@ export class WorkflowContextDebug extends DBOSContextImpl implements WorkflowCon | |
} | ||
// const readOnly = true; // TODO: eventually, this transaction must be read-only. | ||
const funcID = this.functionIDGetIncrement(); | ||
const span: Span = this.#dbosExec.tracer.startSpan(txn.name, {}, this.span); | ||
const span: Span = this.#dbosExec.tracer.startSpan( | ||
txn.name, | ||
{ | ||
operationUUID: this.workflowUUID, | ||
operationType: OperationType.TRANSACTION, | ||
authenticatedUser: this.authenticatedUser, | ||
authenticatedRoles: this.authenticatedRoles, | ||
assumedRole: this.assumedRole, | ||
readOnly: txnInfo.config.readOnly ?? false, // For now doing as in src/workflow.ts:272 | ||
isolationLevel: txnInfo.config.isolationLevel, | ||
}, | ||
this.span | ||
); | ||
let check: RecordedResult<R>; | ||
|
||
const wrappedTransaction = async (client: UserDatabaseClient): Promise<R> => { | ||
|
@@ -126,6 +148,8 @@ export class WorkflowContextDebug extends DBOSContextImpl implements WorkflowCon | |
} | ||
const funcID = this.functionIDGetIncrement(); | ||
|
||
// FIXME: we do not create a span for the replay communicator. Do we want to? | ||
|
||
// Original result must exist during replay. | ||
const check: R | DBOSNull = await this.#dbosExec.systemDatabase.checkOperationOutput<R>(this.workflowUUID, funcID); | ||
if (check === dbosNull) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
/* eslint-disable @typescript-eslint/no-explicit-any */ | ||
import { MethodRegistration, MethodParameter, registerAndWrapFunction, getOrCreateMethodArgsRegistration, MethodRegistrationBase, getRegisteredOperations } from "../decorators"; | ||
import { DBOSExecutor } from "../dbos-executor"; | ||
import { DBOSExecutor, DBOSExecutorIDHeader, OperationType } from "../dbos-executor"; | ||
import { DBOSContext, DBOSContextImpl } from "../context"; | ||
import Koa from "koa"; | ||
import { Workflow, TailParameters, WorkflowHandle, WorkflowParams, WorkflowContext, WFInvokeFuncs } from "../workflow"; | ||
|
@@ -43,22 +43,35 @@ export class HandlerContextImpl extends DBOSContextImpl implements HandlerContex | |
readonly W3CTraceContextPropagator: W3CTraceContextPropagator; | ||
|
||
constructor(dbosExec: DBOSExecutor, readonly koaContext: Koa.Context) { | ||
// Retrieve or generate the request ID | ||
const requestID = getOrGenerateRequestID(koaContext); | ||
|
||
// If present, retrieve the trace context from the request | ||
const httpTracer = new W3CTraceContextPropagator(); | ||
const extractedSpanContext = trace.getSpanContext( | ||
httpTracer.extract(ROOT_CONTEXT, koaContext.request.headers, defaultTextMapGetter) | ||
) | ||
let span: Span; | ||
const spanAttributes = { | ||
operationName: koaContext.url, | ||
operationType: OperationType.HANDLER, | ||
requestID: requestID, | ||
requestIP: koaContext.request.ip, | ||
requestURL: koaContext.request.url, | ||
requestMethod: koaContext.request.method, | ||
}; | ||
if (extractedSpanContext === undefined) { | ||
span = dbosExec.tracer.startSpan(koaContext.url, spanAttributes); | ||
} else { | ||
extractedSpanContext.isRemote = true; | ||
span = dbosExec.tracer.startSpanWithContext(extractedSpanContext, koaContext.url, spanAttributes); | ||
} | ||
|
||
super(koaContext.url, span, dbosExec.logger); | ||
|
||
if (koaContext.request.headers && koaContext.request.headers[DBOSExecutorIDHeader]) { | ||
this.executorID = koaContext.request.headers[DBOSExecutorIDHeader] as string; | ||
} | ||
Comment on lines
+71
to
+73
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now get executor ID as soon as we create the handler context |
||
|
||
this.W3CTraceContextPropagator = httpTracer; | ||
this.request = { | ||
headers: koaContext.request.headers, | ||
|
@@ -72,8 +85,9 @@ export class HandlerContextImpl extends DBOSContextImpl implements HandlerContex | |
querystring: koaContext.request.querystring, | ||
url: koaContext.request.url, | ||
ip: koaContext.request.ip, | ||
requestID: getOrGenerateRequestID(koaContext), | ||
requestID: requestID, | ||
}; | ||
|
||
if (dbosExec.config.application) { | ||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment | ||
this.applicationConfig = dbosExec.config.application; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use the latest version and lock it. These are experimental packages and breaking changes happen often.