diff --git a/.vscode/launch.json b/.vscode/launch.json index a7b2096c41..95d7903cd6 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -105,7 +105,8 @@ "AI_BOT_URL": "http://localhost:4010", "STATS_URL": "http://huly.local:4900", "QUEUE_CONFIG": "localhost:19092", - "FILES_URL": "http://huly.local:4030/blob/:workspace/:blobId/:filename" + "FILES_URL": "http://huly.local:4030/blob/:workspace/:blobId/:filename", + "OTEL_EXPORTER_OTLP_ENDPOINT": "http://huly.local:4318/v1/traces" }, "runtimeArgs": ["--nolazy", "-r", "ts-node/register"], "runtimeVersion": "20", diff --git a/dev/tool/src/index.ts b/dev/tool/src/index.ts index eaa9adb502..ff939b8b6e 100644 --- a/dev/tool/src/index.ts +++ b/dev/tool/src/index.ts @@ -49,7 +49,7 @@ import { registerTxAdapterFactory, setAdapterSecurity } from '@hcengineering/server-pipeline' -import serverToken, { generateToken } from '@hcengineering/server-token' +import serverToken, { decodeToken, generateToken } from '@hcengineering/server-token' import { createWorkspace, upgradeWorkspace } from '@hcengineering/workspace-service' import { faker } from '@faker-js/faker' @@ -1766,12 +1766,12 @@ export function devTool ( } }) - // program - // .command('decode-token ') - // .description('decode token') - // .action(async (token) => { - // console.log(decodeToken(token)) - // }) + program + .command('decode-token ') + .description('decode token') + .action(async (token) => { + console.log(decodeToken(token)) + }) // program // .command('clean-workspace ') diff --git a/packages/core/src/__tests__/contexts.test.ts b/packages/core/src/__tests__/contexts.test.ts index 86ef62b79f..ff93c75bfe 100644 --- a/packages/core/src/__tests__/contexts.test.ts +++ b/packages/core/src/__tests__/contexts.test.ts @@ -5,9 +5,15 @@ describe('context tests', () => { const ctx = new MeasureMetricsContext('test', {}) try { - await ctx.withLog('failed op', {}, async () => { - throw new Error('failed') - }) + await ctx.with( + 'failed op', + {}, + async () => { + throw new Error('failed') + }, + undefined, + { log: true } + ) expect(true).toBe(false) } catch (err: any) { expect(err.message).toBe('failed') diff --git a/packages/core/src/server.ts b/packages/core/src/server.ts index 295822f95a..2af3be288d 100644 --- a/packages/core/src/server.ts +++ b/packages/core/src/server.ts @@ -73,7 +73,7 @@ export interface SessionData { } > - asyncRequests?: ((ctx: MeasureContext) => Promise)[] + asyncRequests?: ((ctx: MeasureContext, id?: string) => Promise)[] } /** diff --git a/packages/measurements-otlp/src/telemetry.ts b/packages/measurements-otlp/src/telemetry.ts index 69e6dde695..1a9068474e 100644 --- a/packages/measurements-otlp/src/telemetry.ts +++ b/packages/measurements-otlp/src/telemetry.ts @@ -12,7 +12,8 @@ import { type FullParamsType, type MeasureLogger, type Metrics, - type ParamsType + type ParamsType, + type WithOptions } from '@hcengineering/measurements' import { context, @@ -27,6 +28,7 @@ import { } from '@opentelemetry/api' import { Logger, SeverityNumber } from '@opentelemetry/api-logs' import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node' +import { suppressTracing } from '@opentelemetry/core' import { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-http' import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http' import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http' @@ -71,6 +73,7 @@ export class OpenTelemetryMetricsContext implements MeasureContext { contextData: object = {} isDone = false doneTrace: string = '' + private done (value?: number, override?: boolean): void { if (!this.isDone) { this.doneTrace = new Error().stack ?? '' @@ -83,7 +86,7 @@ export class OpenTelemetryMetricsContext implements MeasureContext { constructor ( name: string, readonly tracer: Tracer, - readonly context: Context, + readonly context: Context | undefined, readonly span: Span | undefined, params: ParamsType, fullParams: FullParamsType | (() => FullParamsType) = {}, @@ -124,21 +127,28 @@ export class OpenTelemetryMetricsContext implements MeasureContext { newChild ( name: string, params: ParamsType, - fullParams?: FullParamsType | (() => FullParamsType), - logger?: MeasureLogger, - useContextParent?: boolean + opt?: { + fullParams?: FullParamsType + logger?: MeasureLogger + span?: WithOptions['span'] // By default true + } ): MeasureContext { - const childContext = - useContextParent === true || useContextParent == null - ? context.active() - : this.span !== undefined - ? trace.setSpan(this.context, this.span) - : this.context - const span = this.tracer.startSpan(name, undefined, childContext) + let span: Span | undefined + let childContext: Context = context.active() + if (opt?.span === true) { + childContext = + this.span !== undefined + ? trace.setSpan(this.context ?? context.active(), this.span) + : this.context ?? context.active() + span = this.tracer.startSpan(name, undefined, childContext) - const spanParams = [...Object.entries(params)] - for (const [k, v] of spanParams) { - span?.setAttribute(k, v as any) + const spanParams = [...Object.entries(params)] + for (const [k, v] of spanParams) { + span?.setAttribute(k, v as any) + } + } + if (opt?.span === 'disable') { + childContext = suppressTracing(childContext) } const result = new OpenTelemetryMetricsContext( @@ -147,9 +157,9 @@ export class OpenTelemetryMetricsContext implements MeasureContext { childContext, span, params, - fullParams ?? {}, + opt?.fullParams ?? {}, childMetrics(this.metrics, [name]), - logger ?? this.logger, + opt?.logger ?? this.logger, this, this.logParams, this.otlpLogger, @@ -164,16 +174,21 @@ export class OpenTelemetryMetricsContext implements MeasureContext { name: string, params: ParamsType, op: (ctx: MeasureContext) => T | Promise, - fullParams?: ParamsType | (() => FullParamsType) + fullParams?: ParamsType | (() => FullParamsType), + opt?: WithOptions ): Promise { - const c = this.newChild(name, params, fullParams, this.logger, false) + const c = this.newChild(name, opt?.inheritParams === true ? { ...this.params, ...params } : params, { + fullParams, + logger: this.logger, + span: opt?.span ?? true + }) let needFinally = true try { - const _context = (c as OpenTelemetryMetricsContext).context ?? context.active() + const _context = (c as OpenTelemetryMetricsContext).context const span = (c as OpenTelemetryMetricsContext).span - const value = context.with(_context, () => op(c)) + const value = _context !== undefined ? context.with(_context, () => op(c)) : op(c) if (value instanceof Promise) { needFinally = false if (span !== undefined) { @@ -188,12 +203,18 @@ export class OpenTelemetryMetricsContext implements MeasureContext { return value.finally(() => { if (span !== undefined) { const fParams = typeof fullParams === 'function' ? fullParams() : fullParams - const spanParams = [...Object.entries(fParams ?? {})] + const spanParams = [...Object.entries(params), ...Object.entries(fParams ?? {})] for (const [k, v] of spanParams) { - span?.setAttribute(k, v) + span?.setAttribute(k, typeof v === 'object' ? JSON.stringify(v) : v) } } c.end() + if (opt?.log === true) { + this.logger.logOperation(name, platformNowDiff((c as OpenTelemetryMetricsContext).st), { + ...params, + ...fullParams + }) + } }) } else { if (value == null) { @@ -212,45 +233,18 @@ export class OpenTelemetryMetricsContext implements MeasureContext { name: string, params: ParamsType, op: (ctx: MeasureContext) => T, - fullParams?: ParamsType | (() => FullParamsType) + fullParams?: ParamsType | (() => FullParamsType), + opt?: WithOptions ): T { - const c = this.newChild(name, params, fullParams, this.logger, false) - const _context = (c as OpenTelemetryMetricsContext).context ?? context.active() - - const span = (c as OpenTelemetryMetricsContext).span - + const c = this.newChild(name, params, { fullParams, logger: this.logger, span: opt?.span ?? true }) + const _context = (c as OpenTelemetryMetricsContext).context try { - return context.with(_context, () => op(c)) - } catch (err: any) { - if (span !== undefined) { - span.recordException(err) - span?.setStatus({ - code: SpanStatusCode.ERROR, - message: err.message - }) - } - throw err + return _context !== undefined ? context.with(_context, () => op(c)) : op(c) } finally { c.end() } } - withLog( - name: string, - params: ParamsType, - op: (ctx: MeasureContext) => T | Promise, - fullParams?: ParamsType - ): Promise { - const st = platformNow() - const r = this.with(name, params, op, fullParams) - r.catch(() => { - // Ignore logging errors to prevent unhandled rejections - }).finally(() => { - this.logger.logOperation(name, platformNowDiff(st), { ...params, ...fullParams }) - }) - return r - } - error (message: string, args?: Record): void { if (this.otlpLogger !== undefined) { this.otlpLogger.emit({ @@ -503,15 +497,15 @@ export function createOpenTelemetryMetricsContext ( const tracer = trace.getTracer(name) - const otlpLogger = loggerProvider?.getLogger(sdkServiceName ?? name, version) + const otlpLogger = + process.env.OTEL_LOGGER_ENABLED === 'true' ? loggerProvider?.getLogger(sdkServiceName ?? name, version) : undefined const meter = otelMetrics.getMeter(name, version) - const currentConext = context.active() const ctx = new OpenTelemetryMetricsContext( name, tracer, - currentConext, + undefined, undefined, params, fullParams, diff --git a/packages/measurements/src/context.ts b/packages/measurements/src/context.ts index d0773c4f17..be7214c5f5 100644 --- a/packages/measurements/src/context.ts +++ b/packages/measurements/src/context.ts @@ -9,7 +9,8 @@ import { type Metrics, type ParamsType, type OperationLog, - type OperationLogEntry + type OperationLogEntry, + type WithOptions } from './types' const errorPrinter = ({ message, stack, ...rest }: Error): object => ({ @@ -101,15 +102,18 @@ export class MeasureMetricsContext implements MeasureContext { newChild ( name: string, params: ParamsType, - fullParams?: FullParamsType | (() => FullParamsType), - logger?: MeasureLogger + opt?: { + fullParams?: FullParamsType + logger?: MeasureLogger + span?: WithOptions['span'] // By default true + } ): MeasureContext { const result = new MeasureMetricsContext( name, params, - fullParams ?? {}, + opt?.fullParams ?? {}, childMetrics(this.metrics, [name]), - logger ?? this.logger, + opt?.logger ?? this.logger, this, this.logParams ) @@ -122,9 +126,10 @@ export class MeasureMetricsContext implements MeasureContext { name: string, params: ParamsType, op: (ctx: MeasureContext) => T | Promise, - fullParams?: ParamsType | (() => FullParamsType) + fullParams?: ParamsType | (() => FullParamsType), + opt?: WithOptions ): Promise { - const c = this.newChild(name, params, fullParams, this.logger) + const c = this.newChild(name, params, { fullParams, logger: this.logger }) let needFinally = true try { const value = op(c) @@ -132,6 +137,12 @@ export class MeasureMetricsContext implements MeasureContext { needFinally = false return value.finally(() => { c.end() + if (opt?.log === true) { + this.logger.logOperation(name, platformNowDiff((c as MeasureMetricsContext).st), { + ...params, + ...fullParams + }) + } }) } else { if (value == null) { @@ -152,7 +163,7 @@ export class MeasureMetricsContext implements MeasureContext { op: (ctx: MeasureContext) => T, fullParams?: ParamsType | (() => FullParamsType) ): T { - const c = this.newChild(name, params, fullParams, this.logger) + const c = this.newChild(name, params, { fullParams, logger: this.logger }) try { return op(c) } finally { @@ -160,22 +171,6 @@ export class MeasureMetricsContext implements MeasureContext { } } - withLog( - name: string, - params: ParamsType, - op: (ctx: MeasureContext) => T | Promise, - fullParams?: ParamsType - ): Promise { - const st = platformNow() - const r = this.with(name, params, op, fullParams) - r.catch(() => { - // Ignore logging errors to prevent unhandled rejections - }).finally(() => { - this.logger.logOperation(name, platformNowDiff(st), { ...params, ...fullParams }) - }) - return r - } - error (message: string, args?: Record): void { this.logger.error(message, { ...this.params, ...args, ...(this.logParams ?? {}) }) } diff --git a/packages/measurements/src/types.ts b/packages/measurements/src/types.ts index 33d6197f88..496da3d331 100644 --- a/packages/measurements/src/types.ts +++ b/packages/measurements/src/types.ts @@ -64,6 +64,13 @@ export interface MeasureLogger { close: () => Promise } + +export interface WithOptions { + span?: true | false | 'disable' | 'skip' // 'none' means no span will be created, 'disable' means context will be tracing disabled + log?: boolean + inheritParams?: boolean +} + /** * @public */ @@ -76,9 +83,11 @@ export interface MeasureContext { newChild: ( name: string, params: ParamsType, - fullParams?: FullParamsType, - logger?: MeasureLogger, - useContextParent?: boolean + opt?: { + fullParams?: FullParamsType + logger?: MeasureLogger + span?: WithOptions['span'] // By default true + } ) => MeasureContext metrics?: Metrics @@ -87,23 +96,18 @@ export interface MeasureContext { name: string, params: ParamsType, op: (ctx: MeasureContext) => T | Promise, - fullParams?: FullParamsType | (() => FullParamsType) + fullParams?: FullParamsType | (() => FullParamsType), + opt?: WithOptions ) => Promise withSync: ( name: string, params: ParamsType, op: (ctx: MeasureContext) => T, - fullParams?: FullParamsType | (() => FullParamsType) + fullParams?: FullParamsType | (() => FullParamsType), + opt?: WithOptions ) => T - withLog: ( - name: string, - params: ParamsType, - op: (ctx: MeasureContext) => T | Promise, - fullParams?: FullParamsType - ) => Promise - logger: MeasureLogger parent?: MeasureContext diff --git a/pods/server/src/server.ts b/pods/server/src/server.ts index a1290e4e79..936338d86d 100644 --- a/pods/server/src/server.ts +++ b/pods/server/src/server.ts @@ -129,7 +129,7 @@ export function start ( } return await CommunicationApi.create( - ctx.newChild('πŸ’¬ communication api', {}), + ctx.newChild('πŸ’¬ communication api', {}, { span: false }), workspace.uuid, dbUrl, broadcastSessions diff --git a/pods/server/src/server_http.ts b/pods/server/src/server_http.ts index 374b963c16..c01a9a52e3 100644 --- a/pods/server/src/server_http.ts +++ b/pods/server/src/server_http.ts @@ -131,7 +131,7 @@ export function startHttpServer ( const childLogger = ctx.logger.childLogger?.('requests', { enableConsole: 'true' }) - const requests = ctx.newChild('requests', {}, {}, childLogger) + const requests = ctx.newChild('requests', {}, { logger: childLogger, span: false }) class MyStream { write (text: string): void { @@ -430,9 +430,9 @@ export function startHttpServer ( void retrieveJson(req) .then((data) => { if (Array.isArray(data)) { - sessions.broadcastAll(ws, data as Tx[]) + sessions.broadcastAll(ctx, ws, data as Tx[]) } else { - sessions.broadcastAll(ws, [data as unknown as Tx]) + sessions.broadcastAll(ctx, ws, [data as unknown as Tx]) } res.end() }) diff --git a/server-plugins/calendar-resources/src/index.ts b/server-plugins/calendar-resources/src/index.ts index 044b8f74e6..fecd2d442a 100644 --- a/server-plugins/calendar-resources/src/index.ts +++ b/server-plugins/calendar-resources/src/index.ts @@ -346,7 +346,7 @@ async function putEventToQueue ( ): Promise { if (control.queue === undefined) return const producer = control.queue.getProducer( - control.ctx.newChild('queue', {}), + control.ctx.newChild('queue', {}, { span: false }), QueueTopic.CalendarEventCUD ) diff --git a/server/account-service/src/index.ts b/server/account-service/src/index.ts index 3e039eaaf8..e0d955a690 100644 --- a/server/account-service/src/index.ts +++ b/server/account-service/src/index.ts @@ -128,7 +128,8 @@ export function serveAccount (measureCtx: MeasureContext, brandings: BrandingMap setMetadata(account.metadata.WsLivenessDays, wsLivenessDays) setMetadata(serverToken.metadata.Secret, serverSecret) - setMetadata(serverToken.metadata.Service, 'account') + // Force undefied, for user tokens do not include service + setMetadata(serverToken.metadata.Service, undefined) const hasSignUp = process.env.DISABLE_SIGNUP !== 'true' const methods = getMethods(hasSignUp) @@ -385,27 +386,28 @@ export function serveAccount (measureCtx: MeasureContext, brandings: BrandingMap // Ignore } - const userCtx = measureCtx.newChild(request.method, { source }) + await measureCtx.with( + request.method, + { source }, + async (_ctx) => { + if (method === undefined || typeof method !== 'function') { + const response = { + id: request.id, + error: new Status(Severity.ERROR, platform.status.UnknownMethod, { method: request.method }) + } - try { - if (method === undefined || typeof method !== 'function') { - const response = { - id: request.id, - error: new Status(Severity.ERROR, platform.status.UnknownMethod, { method: request.method }) + ctx.body = JSON.stringify(response) + return } - ctx.body = JSON.stringify(response) - return - } + const result = await method(_ctx, db, branding, request, token, meta) - const result = await method(userCtx, db, branding, request, token, meta) - - const body = JSON.stringify(result) - ctx.res.writeHead(200, KEEP_ALIVE_HEADERS) - ctx.res.end(body) - } finally { - userCtx.end() - } + const body = JSON.stringify(result) + ctx.res.writeHead(200, KEEP_ALIVE_HEADERS) + ctx.res.end(body) + }, + { ...request } + ) }) app.use(router.routes()).use(router.allowedMethods()) diff --git a/server/backup/src/backup.ts b/server/backup/src/backup.ts index d557880d36..67a9d23d84 100644 --- a/server/backup/src/backup.ts +++ b/server/backup/src/backup.ts @@ -103,7 +103,7 @@ export async function backup ( backupSize: 0 } const workspaceId = wsIds.uuid - ctx = ctx.newChild('backup', {}) + ctx = ctx.newChild('backup', {}, { span: false }) let _canceled = false const canceled = (): boolean => { diff --git a/server/backup/src/service.ts b/server/backup/src/service.ts index b8de4127a2..c48f3e2874 100644 --- a/server/backup/src/service.ts +++ b/server/backup/src/service.ts @@ -293,7 +293,7 @@ class BackupWorker { url: ws.url, dataId: ws.dataId }) - const ctx = rootCtx.newChild('doBackup', {}) + const ctx = rootCtx.newChild('doBackup', {}, { span: false }) const dataId = ws.dataId ?? (ws.uuid as unknown as WorkspaceDataId) let pipeline: Pipeline | undefined const backupIds = { @@ -446,7 +446,7 @@ export async function doRestoreWorkspace ( workspace: wsIds.uuid, dataId: wsIds.dataId }) - const ctx = rootCtx.newChild('doRestore', {}) + const ctx = rootCtx.newChild('doRestore', {}, { span: false }) let pipeline: Pipeline | undefined try { pipeline = await pipelineFactory( diff --git a/server/collaborator/src/server.ts b/server/collaborator/src/server.ts index 341992c274..cd8f49f272 100644 --- a/server/collaborator/src/server.ts +++ b/server/collaborator/src/server.ts @@ -54,7 +54,7 @@ export async function start (ctx: MeasureContext, config: Config, storageAdapter app.use(express.json({ limit: '10mb' })) app.use(bp.json({ limit: '10mb' })) - const extensionsCtx = ctx.newChild('extensions', {}) + const extensionsCtx = ctx.newChild('extensions', {}, { span: false }) const transformer = new MarkupTransformer() const hocuspocus = new Hocuspocus({ @@ -94,17 +94,17 @@ export async function start (ctx: MeasureContext, config: Config, storageAdapter extensions: [ new AuthenticationExtension({ - ctx: extensionsCtx.newChild('authenticate', {}) + ctx: extensionsCtx.newChild('authenticate', {}, { span: false }) }), new StorageExtension({ - ctx: extensionsCtx.newChild('storage', {}), + ctx: extensionsCtx.newChild('storage', {}, { span: false }), adapter: new PlatformStorageAdapter(storageAdapter, { retryCount, retryInterval }), transformer }) ] }) - const rpcCtx = ctx.newChild('rpc', {}) + const rpcCtx = ctx.newChild('rpc', {}, { span: false }) const getContext = async (rawToken: string, token: Token): Promise => { const wsIds = await getWorkspaceIds(rawToken) diff --git a/server/core/src/dbAdapterManager.ts b/server/core/src/dbAdapterManager.ts index 807718b8bc..1f7b8153e9 100644 --- a/server/core/src/dbAdapterManager.ts +++ b/server/core/src/dbAdapterManager.ts @@ -73,39 +73,51 @@ export class DbAdapterManagerImpl implements DBAdapterManager { const adapterDomains = new Map>() for (const d of this.context.hierarchy.domains()) { // We need to init domain info - await ctx.with('update-info', { domain: d }, async (ctx) => { - const info = this.getDomainInfo(d) - await this.updateInfo(d, adapterDomains, info) - }) + await ctx.with( + 'update-info', + { domain: d }, + async (ctx) => { + const info = this.getDomainInfo(d) + await this.updateInfo(d, adapterDomains, info) + }, + undefined, + { span: false } + ) } for (const [name, adapter] of this.adapters.entries()) { - await ctx.with('domain-helper', { name }, async (ctx) => { - adapter.on?.((domain, event, count, helper) => { - const info = this.getDomainInfo(domain) - const oldDocuments = info.documents - switch (event) { - case 'add': - info.documents += count - break - case 'update': - break - case 'delete': - info.documents -= count - break - case 'read': - break - } + await ctx.with( + 'domain-helper', + { name }, + async (ctx) => { + adapter.on?.((domain, event, count, helper) => { + const info = this.getDomainInfo(domain) + const oldDocuments = info.documents + switch (event) { + case 'add': + info.documents += count + break + case 'update': + break + case 'delete': + info.documents -= count + break + case 'read': + break + } - if (oldDocuments < 50 && info.documents > 50) { - // We have more 50 documents, we need to check for indexes - void this.domainHelper?.checkDomain(this.metrics, domain, info.documents, helper) - } - if (oldDocuments > 50 && info.documents < 50) { - // We have more 50 documents, we need to check for indexes - void this.domainHelper?.checkDomain(this.metrics, domain, info.documents, helper) - } - }) - }) + if (oldDocuments < 50 && info.documents > 50) { + // We have more 50 documents, we need to check for indexes + void this.domainHelper?.checkDomain(this.metrics, domain, info.documents, helper) + } + if (oldDocuments > 50 && info.documents < 50) { + // We have more 50 documents, we need to check for indexes + void this.domainHelper?.checkDomain(this.metrics, domain, info.documents, helper) + } + }) + }, + undefined, + { span: false } + ) } } diff --git a/server/core/src/stats.ts b/server/core/src/stats.ts index 20126418b0..4cfac0b184 100644 --- a/server/core/src/stats.ts +++ b/server/core/src/stats.ts @@ -128,18 +128,26 @@ export function initStatisticsContext ( const statData = JSON.stringify(data) - prev = fetch(concatLink(statsUrl, '/api/v1/statistics') + `/?name=${serviceId}`, { - method: 'PUT', - headers: { - 'Content-Type': 'application/json', - authorization: `Bearer ${token}` + void metricsContext.with( + 'sendStatistics', + {}, + async (ctx) => { + prev = fetch(concatLink(statsUrl, '/api/v1/statistics') + `/?name=${serviceId}`, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + authorization: `Bearer ${token}` + }, + body: statData + }) + .finally(() => { + prev = undefined + }) + .catch(handleError) }, - body: statData - }) - .finally(() => { - prev = undefined - }) - .catch(handleError) + undefined, + { span: 'disable' } + ) } } catch (err: any) { handleError(err) diff --git a/server/core/src/types.ts b/server/core/src/types.ts index 2af00997ba..fa7f1db36a 100644 --- a/server/core/src/types.ts +++ b/server/core/src/types.ts @@ -721,6 +721,7 @@ export interface SessionManager { ) => Promise broadcastAll: ( + ctx: MeasureContext, workspace: WorkspaceUuid, tx: Tx[], targets?: AccountUuid | AccountUuid[], diff --git a/server/front/src/index.ts b/server/front/src/index.ts index 9cc79452ba..e354063d1c 100644 --- a/server/front/src/index.ts +++ b/server/front/src/index.ts @@ -317,7 +317,7 @@ export function start ( const childLogger = ctx.logger.childLogger?.('requests', { enableConsole: 'true' }) - const requests = ctx.newChild('requests', {}, {}, childLogger) + const requests = ctx.newChild('requests', {}, { logger: childLogger, span: false }) class MyStream { write (text: string): void { diff --git a/server/middleware/src/contextName.ts b/server/middleware/src/contextName.ts index b4a4f8cf66..c91c49bed8 100644 --- a/server/middleware/src/contextName.ts +++ b/server/middleware/src/contextName.ts @@ -68,8 +68,10 @@ export class ContextNameMiddleware extends BaseMiddleware implements Middleware let opLogMetrics: Metrics | undefined const result = await ctx.with( - measureName !== undefined ? `πŸ“Ά ${measureName}` : 'client-tx', - { source: ctx.contextData.service }, + 'client-tx', + measureName !== undefined + ? { measureName, source: ctx.contextData.service } + : { source: ctx.contextData.service }, (ctx) => { ;({ opLogMetrics, op } = registerOperationLog(ctx)) return this.provideTx(ctx, txes) diff --git a/server/middleware/src/dbAdapter.ts b/server/middleware/src/dbAdapter.ts index 4cd7825e5c..a01ce85a53 100644 --- a/server/middleware/src/dbAdapter.ts +++ b/server/middleware/src/dbAdapter.ts @@ -65,7 +65,7 @@ export class DBAdapterMiddleware extends BaseMiddleware implements Middleware { } }) - const metrics = ctx.newChild('πŸ“” adapters', {}) + const metrics = ctx.newChild('πŸ“” adapters', {}, { span: false }) const txAdapterName = this.conf.domains[DOMAIN_TX] const txAdapter = adapters.get(txAdapterName) as TxAdapter diff --git a/server/middleware/src/triggers.ts b/server/middleware/src/triggers.ts index f06f772a25..cd4a8be867 100644 --- a/server/middleware/src/triggers.ts +++ b/server/middleware/src/triggers.ts @@ -184,7 +184,9 @@ export class TriggersMiddleware extends BaseMiddleware implements Middleware { } else { ctx.contextData.asyncRequests = [ ...(ctx.contextData.asyncRequests ?? []), - async (ctx) => { + async (_ctx, id?: string) => { + // Just replace id of previous context + ctx.id = id // In case of async context, we execute both async and sync triggers as sync await this.processAsyncTriggers(ctx, triggerControl, findAll, txes, triggers) } diff --git a/server/middleware/src/txPush.ts b/server/middleware/src/txPush.ts index c626d17667..a898ff6159 100644 --- a/server/middleware/src/txPush.ts +++ b/server/middleware/src/txPush.ts @@ -66,7 +66,7 @@ export class TxMiddleware extends BaseMiddleware implements Middleware { let txPromise: Promise | undefined if (txToStore.length > 0) { txPromise = ctx.with( - 'domain-tx', + 'tx-push', {}, (ctx) => this.adapterManager.getAdapter(DOMAIN_TX, true).tx(ctx, ...txToStore), { diff --git a/server/postgres/src/storage.ts b/server/postgres/src/storage.ts index aab59f08c1..34ee36e501 100644 --- a/server/postgres/src/storage.ts +++ b/server/postgres/src/storage.ts @@ -1781,6 +1781,7 @@ export class PostgresAdapter extends PostgresAdapterBase { } return undefined }) + for (const [domain, txs] of byDomain) { if (domain === undefined) { continue @@ -1958,7 +1959,7 @@ export class PostgresAdapter extends PostgresAdapterBase { WHERE "workspaceId" = $1::uuid AND "_id" = update_data.__id` await this.mgr.retry(ctx.id, this.mgrId, (client) => - ctx.with('bulk-update', {}, () => client.execute(op, data)) + _ctx.with('bulk-update', {}, () => client.execute(op, data)) ) } } diff --git a/server/server-pipeline/src/pipeline.ts b/server/server-pipeline/src/pipeline.ts index 7011fe2696..bffe65d265 100644 --- a/server/server-pipeline/src/pipeline.ts +++ b/server/server-pipeline/src/pipeline.ts @@ -113,7 +113,7 @@ export function createServerPipeline ( ): PipelineFactory { return (ctx, workspace, broadcast, branding) => { const metricsCtx = opt.usePassedCtx === true ? ctx : metrics - const wsMetrics = metricsCtx.newChild('🧲 session', {}) + const wsMetrics = metricsCtx.newChild('🧲 session', {}, { span: false }) const conf = getConfig(metrics, dbUrl, wsMetrics, opt, extensions) const middlewares: MiddlewareCreator[] = [ @@ -189,7 +189,7 @@ export function createBackupPipeline ( ): PipelineFactory { return (ctx, workspace, broadcast, branding) => { const metricsCtx = opt.usePassedCtx === true ? ctx : metrics - const wsMetrics = metricsCtx.newChild('🧲 backup', {}) + const wsMetrics = metricsCtx.newChild('🧲 backup', {}, { span: false }) const conf = getConfig(metrics, dbUrl, wsMetrics, { ...opt, disableTriggers: true @@ -336,7 +336,7 @@ export function getConfig ( extensions?: Partial ): DbConfiguration { const metricsCtx = opt.usePassedCtx === true ? ctx : metrics - const wsMetrics = metricsCtx.newChild('🧲 session', {}) + const wsMetrics = metricsCtx.newChild('🧲 session', {}, { span: false }) const conf: DbConfiguration = { domains: { [DOMAIN_TX]: 'Tx', diff --git a/server/server/src/client.ts b/server/server/src/client.ts index 92a8a2bfff..6381ef9d0a 100644 --- a/server/server/src/client.ts +++ b/server/server/src/client.ts @@ -128,7 +128,7 @@ export class ClientSession implements Session { async loadModel (ctx: ClientSessionCtx, lastModelTx: Timestamp, hash?: string): Promise { try { this.includeSessionContext(ctx) - const result = await ctx.ctx.with('load-model', {}, () => ctx.pipeline.loadModel(ctx.ctx, lastModelTx, hash)) + const result = await ctx.pipeline.loadModel(ctx.ctx, lastModelTx, hash) await ctx.sendResponse(ctx.requestId, result) } catch (err) { await ctx.sendError(ctx.requestId, 'Failed to loadModel', unknownError(err)) @@ -244,7 +244,7 @@ export class ClientSession implements Session { const handleAyncs = async (): Promise => { try { for (const r of asyncs) { - await r(ctx.ctx) + await r(ctx.ctx, cid) } } finally { onEnd?.() diff --git a/server/server/src/sessionManager.ts b/server/server/src/sessionManager.ts index ab8a6b1de7..533288dbca 100644 --- a/server/server/src/sessionManager.ts +++ b/server/server/src/sessionManager.ts @@ -141,10 +141,10 @@ export class TSessionManager implements SessionManager { this.handleTick() }, 1000 / ticksPerSecond) } - this.workspaceProducer = this.queue.getProducer(ctx.newChild('queue', {}), QueueTopic.Workspace) - this.usersProducer = this.queue.getProducer(ctx.newChild('queue', {}), QueueTopic.Users) + this.workspaceProducer = this.queue.getProducer(ctx.newChild('queue', {}, { span: false }), QueueTopic.Workspace) + this.usersProducer = this.queue.getProducer(ctx.newChild('queue', {}, { span: false }), QueueTopic.Users) - this.ticksContext = ctx.newChild('ticks', {}, undefined, undefined, false) + this.ticksContext = ctx.newChild('ticks', {}, { span: false }) } scheduleMaintenance (timeMinutes: number, message?: string): void { @@ -177,7 +177,7 @@ export class TSessionManager implements SessionManager { } const event: TxWorkspaceEvent = this.createMaintenanceWarning() for (const ws of this.workspaces.values()) { - this.doBroadcast(ws, [event]) + this.doBroadcast(this.ctx, ws, [event]) } } @@ -642,6 +642,7 @@ export class TSessionManager implements SessionManager { } broadcastAll ( + ctx: MeasureContext, workspace: WorkspaceUuid, tx: Tx[], target?: AccountUuid | AccountUuid[], @@ -651,17 +652,23 @@ export class TSessionManager implements SessionManager { if (ws === undefined) { return } - this.doBroadcast(ws, tx, target, exclude) + this.doBroadcast(ctx, ws, tx, target, exclude) } - doBroadcast (ws: Workspace, tx: Tx[], target?: AccountUuid | AccountUuid[], exclude?: AccountUuid[]): void { + doBroadcast ( + ctx: MeasureContext, + ws: Workspace, + tx: Tx[], + target?: AccountUuid | AccountUuid[], + exclude?: AccountUuid[] + ): void { if (ws.maintenance) { return } if (target !== undefined && !Array.isArray(target)) { target = [target] } - const ctx = this.ctx.newChild('πŸ“¬ broadcast-all', {}) + ctx = ctx.newChild('πŸ“¬ broadcast-all', {}) const sessions = [...ws.sessions.values()].filter((it) => { if (it === undefined) { return false @@ -726,6 +733,7 @@ export class TSessionManager implements SessionManager { } broadcast ( + ctx: MeasureContext, from: Session | null, workspaceId: WorkspaceUuid, resp: Tx[], @@ -746,7 +754,7 @@ export class TSessionManager implements SessionManager { } const sessions = [...workspace.sessions.values()] - const ctx = this.ctx.newChild('πŸ“­ broadcast', {}) + ctx = ctx.newChild('πŸ“­ broadcast', {}) const send = (): void => { for (const sessionRef of sessions) { const tt = sessionRef.session.getUser() @@ -773,7 +781,7 @@ export class TSessionManager implements SessionManager { branding: Branding | null ): Workspace { const upgrade = token.extra?.model === 'upgrade' - const context = ctx.newChild('🧲 session', {}) + const context = ctx.newChild('🧲 session', {}, { span: false }) const workspaceIds: WorkspaceIds = { uuid: token.workspace, dataId: workspaceDataId, @@ -786,7 +794,7 @@ export class TSessionManager implements SessionManager { workspaceIds, { broadcast: (ctx, tx, targets, exclude) => { - this.broadcastAll(workspaceIds.uuid, tx, targets, exclude) + this.broadcastAll(ctx, workspaceIds.uuid, tx, targets, exclude) }, broadcastSessions: (ctx, sessions) => { this.broadcastSessions(ctx, sessions) @@ -1169,14 +1177,6 @@ export class TSessionManager implements SessionManager { return this.limitter.checkRateLimit(service.getUser() + (service.token.extra?.service ?? '')) } - getUserCtx (requestCtx: MeasureContext, service: Session, mode: string): MeasureContext { - const userCtx = requestCtx.newChild('πŸ“ž client', { - source: service.token.extra?.service ?? 'πŸ€¦β€β™‚οΈuser', - mode - }) - return userCtx - } - async handleRequest( requestCtx: MeasureContext, service: S, @@ -1184,10 +1184,10 @@ export class TSessionManager implements SessionManager { request: Request, workspaceId: WorkspaceUuid ): Promise { - const userCtx = this.getUserCtx(requestCtx, service, '🧭 handleRequest') - // Calculate total number of clients const reqId = generateId() + const mode = 'request' + const source = service.token.extra?.service ?? 'πŸ€¦β€β™‚οΈuser' const st = Date.now() try { @@ -1198,7 +1198,7 @@ export class TSessionManager implements SessionManager { const workspace = this.workspaces.get(workspaceId) if (workspace === undefined || workspace.closing !== undefined) { await ws.send( - userCtx, + requestCtx, { id: request.id, error: unknownError('Workspace is closing') @@ -1209,7 +1209,9 @@ export class TSessionManager implements SessionManager { return } if (request.id === -1 && request.method === 'hello') { - await this.handleHello(request, service, userCtx, workspace, ws, requestCtx) + await requestCtx.with('handleHello', { mode, source }, (ctx) => + this.handleHello(request, service, ctx, workspace, ws, requestCtx) + ) return } if (request.id === -2 && request.method === 'forceClose') { @@ -1226,7 +1228,7 @@ export class TSessionManager implements SessionManager { id: request.id, result: done } - await ws.send(userCtx, forceCloseResponse, service.binaryMode, service.useCompression) + await ws.send(requestCtx, forceCloseResponse, service.binaryMode, service.useCompression) return } let rateLimit: RateLimitInfo | undefined @@ -1236,7 +1238,7 @@ export class TSessionManager implements SessionManager { if (rateLimit?.remaining === 0) { service.updateLast() void ws.send( - userCtx, + requestCtx, { id: request.id, rateLimit, @@ -1264,15 +1266,19 @@ export class TSessionManager implements SessionManager { const params = [...request.params] if (ws.isBackpressure()) { - await ws.backpressure(userCtx) + await ws.backpressure(requestCtx) } await workspace.with(async (pipeline) => { - await userCtx.with('🧨 process', {}, (callTx) => - f.apply(service, [ - this.createOpContext(callTx, userCtx, pipeline, request.id, service, ws, rateLimit), - ...params - ]) + await requestCtx.with( + '🧨' + request.method, + { mode, source }, + (callTx) => + f.apply(service, [ + this.createOpContext(callTx, requestCtx, pipeline, request.id, service, ws, rateLimit), + ...params + ]), + { ...request, user: service.getUser, socialId: service.getRawAccount().primarySocialId } ) }) } catch (err: any) { @@ -1281,7 +1287,7 @@ export class TSessionManager implements SessionManager { this.ctx.error('error handle request', { error: err, request }) } await ws.send( - userCtx, + requestCtx, { id: request.id, error: unknownError(err), @@ -1292,7 +1298,6 @@ export class TSessionManager implements SessionManager { ) } } finally { - userCtx.end() service.requests.delete(reqId) } } @@ -1309,7 +1314,8 @@ export class TSessionManager implements SessionManager { return await Promise.resolve(rateLimitStatus) } - const userCtx = this.getUserCtx(requestCtx, service, '🧭 handleRPC') + const mode = 'rpc' + const source = service.token.extra?.service ?? 'πŸ€¦β€β™‚οΈuser' // Calculate total number of clients const reqId = generateId() @@ -1329,9 +1335,9 @@ export class TSessionManager implements SessionManager { try { await workspace.with(async (pipeline) => { - await userCtx.with('🧨 process', {}, (callTx) => + await requestCtx.with('🧨 handleRequest', { mode, source }, (callTx) => operation( - this.createOpContext(callTx, userCtx, pipeline, reqId, service, ws, rateLimitStatus), + this.createOpContext(callTx, requestCtx, pipeline, reqId, service, ws, rateLimitStatus), rateLimitStatus ) ) @@ -1342,7 +1348,7 @@ export class TSessionManager implements SessionManager { this.ctx.error('error handle request', { error: err }) } await ws.send( - userCtx, + requestCtx, { id: reqId, error: unknownError(err), @@ -1355,7 +1361,6 @@ export class TSessionManager implements SessionManager { } return undefined } finally { - userCtx.end() service.requests.delete(reqId) } } diff --git a/server/workspace-service/src/ws-operations.ts b/server/workspace-service/src/ws-operations.ts index c5c9714440..963af4dafa 100644 --- a/server/workspace-service/src/ws-operations.ts +++ b/server/workspace-service/src/ws-operations.ts @@ -50,7 +50,7 @@ export async function createWorkspace ( ) => Promise, external: boolean = false ): Promise { - const childLogger = ctx.newChild('createWorkspace', ctx.getParams(), {}) + const childLogger = ctx.newChild('createWorkspace', ctx.getParams()) const ctxModellogger: ModelLogger = { log: (msg, data) => { childLogger.info(msg, data) @@ -92,8 +92,12 @@ export async function createWorkspace ( usePassedCtx: true }) const txAdapter = await txFactory(ctx, hierarchy, dbUrl, wsIds, modelDb, storageAdapter) - await childLogger.withLog('init-workspace', {}, (ctx) => - initModel(ctx, wsId, txes, txAdapter, storageAdapter, ctxModellogger, async (value) => {}) + await childLogger.with( + 'init-workspace', + {}, + (ctx) => initModel(ctx, wsId, txes, txAdapter, storageAdapter, ctxModellogger, async (value) => {}), + { workspace: wsId }, + { log: true } ) const client = new TxOperations(wrapPipeline(ctx, pipeline, wsIds), core.account.ConfigUser) diff --git a/services/ai-bot/pod-ai-bot/src/controller.ts b/services/ai-bot/pod-ai-bot/src/controller.ts index f4ec519f93..6ff6063a29 100644 --- a/services/ai-bot/pod-ai-bot/src/controller.ts +++ b/services/ai-bot/pod-ai-bot/src/controller.ts @@ -163,7 +163,7 @@ export class AIControl { wsIds, this.personUuid, this.socialIds, - this.ctx.newChild('create-workspace', {}), + this.ctx.newChild('create-workspace', {}, { span: false }), this.openai, this.openaiEncoding, info diff --git a/services/ai-bot/pod-ai-bot/src/workspace/workspaceClient.ts b/services/ai-bot/pod-ai-bot/src/workspace/workspaceClient.ts index 8f41040d9d..e68e00f2d0 100644 --- a/services/ai-bot/pod-ai-bot/src/workspace/workspaceClient.ts +++ b/services/ai-bot/pod-ai-bot/src/workspace/workspaceClient.ts @@ -127,7 +127,7 @@ export class WorkspaceClient { if (this.aiPerson !== undefined && config.LoveEndpoint !== '') { this.love = new LoveController( this.wsIds.uuid, - this.ctx.newChild('love', {}), + this.ctx.newChild('love', {}, { span: false }), this.token, opClient, this.aiPerson diff --git a/services/backup/backup-api-pod/src/server.ts b/services/backup/backup-api-pod/src/server.ts index 93133d15d1..705f595b54 100644 --- a/services/backup/backup-api-pod/src/server.ts +++ b/services/backup/backup-api-pod/src/server.ts @@ -127,7 +127,7 @@ export async function createServer (ctx: MeasureContext, config: Config): Promis app.use(keepAlive({ timeout: KEEP_ALIVE_TIMEOUT, max: KEEP_ALIVE_MAX })) const childLogger = ctx.logger.childLogger?.('requests', { enableConsole: 'true' }) - const requests = ctx.newChild('requests', {}, {}, childLogger) + const requests = ctx.newChild('requests', {}, { logger: childLogger, span: false }) class LogStream { write (text: string): void { requests.info(text) diff --git a/services/billing/pod-billing/src/server.ts b/services/billing/pod-billing/src/server.ts index aa923bdf0d..9148bfb66c 100644 --- a/services/billing/pod-billing/src/server.ts +++ b/services/billing/pod-billing/src/server.ts @@ -90,7 +90,7 @@ export async function createServer (ctx: MeasureContext, config: Config): Promis app.use(express.json({ limit: '50mb' })) const childLogger = ctx.logger.childLogger?.('requests', { enableConsole: 'true' }) - const requests = ctx.newChild('requests', {}, {}, childLogger) + const requests = ctx.newChild('requests', {}, { logger: childLogger, span: false }) class LogStream { write (text: string): void { requests.info(text) diff --git a/services/datalake/pod-datalake/src/server.ts b/services/datalake/pod-datalake/src/server.ts index 089527e225..d670a4e5cf 100644 --- a/services/datalake/pod-datalake/src/server.ts +++ b/services/datalake/pod-datalake/src/server.ts @@ -132,7 +132,7 @@ export async function createServer ( } } - const producer = queue.getProducer(ctx.newChild('queue', {}), QueueTopic.Tx) + const producer = queue.getProducer(ctx.newChild('queue', {}, { span: false }), QueueTopic.Tx) const db = await createDb(ctx, config.DbUrl) const datalake = new DatalakeImpl(db, buckets, producer, { cacheControl }) @@ -145,7 +145,7 @@ export async function createServer ( app.use(keepAlive({ timeout: KEEP_ALIVE_TIMEOUT, max: KEEP_ALIVE_MAX })) const childLogger = ctx.logger.childLogger?.('requests', { enableConsole: 'true' }) - const requests = ctx.newChild('requests', {}, {}, childLogger) + const requests = ctx.newChild('requests', {}, { logger: childLogger, span: false }) class LogStream { write (text: string): void { requests.info(text) diff --git a/services/github/pod-github/src/platform.ts b/services/github/pod-github/src/platform.ts index 4264fda3a7..3695189444 100644 --- a/services/github/pod-github/src/platform.ts +++ b/services/github/pod-github/src/platform.ts @@ -1007,7 +1007,7 @@ export class PlatformWorker { } try { const branding = Object.values(this.brandingMap).find((b) => b.key === workspaceInfo?.branding) ?? null - const workerCtx = this.ctx.newChild('worker', { workspace: workspaceInfo.uuid }, {}) + const workerCtx = this.ctx.newChild('worker', { workspace: workspaceInfo.uuid }, { span: false }) connecting.set(workspaceInfo.uuid, { time: Date.now(), @@ -1157,8 +1157,10 @@ export class PlatformWorker { const webhook = this.ctx.newChild( 'webhook', {}, - {}, - new SplitLogger('webhook', { root: join(process.cwd(), 'logs'), pretty: true, enableConsole: false }) + { + logger: new SplitLogger('webhook', { root: join(process.cwd(), 'logs'), pretty: true, enableConsole: false }), + span: false + } ) webhook.info('Register webhook') diff --git a/services/github/pod-github/src/sync/issueBase.ts b/services/github/pod-github/src/sync/issueBase.ts index af6e72e363..f11a1c3079 100644 --- a/services/github/pod-github/src/sync/issueBase.ts +++ b/services/github/pod-github/src/sync/issueBase.ts @@ -271,7 +271,7 @@ export abstract class IssueSyncManagerBase { ): Promise> { let needUpdate = false if (!this.client.getHierarchy().hasMixin(existing, github.mixin.GithubIssue)) { - await this.ctx.withLog( + await this.ctx.with( 'create mixin issue: GithubIssue', {}, async () => { @@ -288,7 +288,8 @@ export abstract class IssueSyncManagerBase { ) await this.notifyConnected(container, info, existing, issueExternal) }, - { identifier: existing.identifier, url: issueExternal.url } + { identifier: existing.identifier, url: issueExternal.url }, + { log: true } ) // Re iterate to have existing value with mixin inside. needUpdate = true diff --git a/services/github/pod-github/src/sync/issues.ts b/services/github/pod-github/src/sync/issues.ts index acda90aaa4..e918b511fd 100644 --- a/services/github/pod-github/src/sync/issues.ts +++ b/services/github/pod-github/src/sync/issues.ts @@ -339,24 +339,31 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan return { needSync: githubSyncVersion } } - const description = await this.ctx.withLog('query collaborative description', {}, async () => { - const collabId = makeDocCollabId(existing, 'description') - return await this.collaborator.getMarkup(collabId, (existing as Issue).description) - }) + const description = await this.ctx.with( + 'query collaborative description', + {}, + async () => { + const collabId = makeDocCollabId(existing, 'description') + return await this.collaborator.getMarkup(collabId, (existing as Issue).description) + }, + {}, + { log: true } + ) this.ctx.info('create github issue', { title: (existing as Issue).title, number: (existing as Issue).number, workspace: this.provider.getWorkspaceId() }) - const createdIssueData = await this.ctx.withLog( + const createdIssueData = await this.ctx.with( 'create github issue', {}, async () => { this.createPromise = this.createGithubIssue(container, { ...(existing as Issue), description }, repository) return await this.createPromise }, - { id: (existing as Issue).identifier, workspace: this.provider.getWorkspaceId() } + { id: (existing as Issue).identifier, workspace: this.provider.getWorkspaceId() }, + { log: true } ) if (createdIssueData === undefined) { this.ctx.error('Error create issue', { url: info.url }) @@ -476,7 +483,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan // No repository, it probable deleted return { needSync: githubSyncVersion } } - await this.ctx.withLog( + await this.ctx.with( 'create platform issue', {}, async () => { @@ -499,7 +506,8 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan !markdownCompatible ) }, - { url: issueExternal.url } + { url: issueExternal.url }, + { log: true } ) // We need reiterate to update all sync data. return { @@ -518,17 +526,18 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan } } else { try { - const description = await this.ctx.withLog( + const description = await this.ctx.with( 'query collaborative description', {}, async () => { const collabId = makeDocCollabId(existing, 'description') return await this.collaborator.getMarkup(collabId, (existing as Issue).description) }, - { url: issueExternal.url } + { url: issueExternal.url }, + { log: true } ) - const updateResult = await this.ctx.withLog( + const updateResult = await this.ctx.with( 'diff update', {}, async () => @@ -541,7 +550,8 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan account, accountGH ), - { url: issueExternal.url } + { url: issueExternal.url }, + { log: true } ) return { ...updateResult, @@ -620,7 +630,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan if (hasFieldStateChanges || body !== undefined) { if (body !== undefined && !isLocked) { - await this.ctx.withLog( + await this.ctx.with( '==> updateIssue', {}, async () => { @@ -656,11 +666,12 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan } } }, - { url: issueExternal.url, id: existing._id } + { url: issueExternal.url, id: existing._id }, + { log: true } ) issueData.description = await this.provider.getMarkupSafe(container.container, body, this.stripGuestLink) } else if (hasFieldStateChanges) { - await this.ctx.withLog( + await this.ctx.with( '==> updateIssue', {}, async () => { @@ -693,7 +704,8 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan } } }, - { url: issueExternal.url } + { url: issueExternal.url }, + { log: true } ) } return true diff --git a/services/github/pod-github/src/sync/pullrequests.ts b/services/github/pod-github/src/sync/pullrequests.ts index b9a018495f..039573b6b5 100644 --- a/services/github/pod-github/src/sync/pullrequests.ts +++ b/services/github/pod-github/src/sync/pullrequests.ts @@ -415,7 +415,7 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS if (existing === undefined) { try { - await this.ctx.withLog( + await this.ctx.with( 'retrieve pull request patch', {}, () => @@ -431,7 +431,8 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS lastModified, accountGH ), - { url: pullRequestExternal.url } + { url: pullRequestExternal.url }, + { log: true } ) const { markdownCompatible, markdown } = await this.provider.checkMarkdownConversion( container.container, @@ -441,7 +442,7 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS let op = this.client.apply() let createdPullRequest: GithubPullRequest | undefined - await this.ctx.withLog( + await this.ctx.with( 'create pull request in platform', {}, async () => { @@ -461,7 +462,8 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS !markdownCompatible ) }, - { url: pullRequestExternal.url } + { url: pullRequestExternal.url }, + { log: true } ) await op.commit() @@ -499,7 +501,7 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS } else { try { if (info.updatePatch === true) { - await this.ctx.withLog( + await this.ctx.with( 'update pull request patch', {}, () => @@ -515,21 +517,23 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS lastModified, accountGH ), - { url: pullRequestExternal.url } + { url: pullRequestExternal.url }, + { log: true } ) } - const description = await this.ctx.withLog( + const description = await this.ctx.with( 'query collaborative pull request description', {}, async () => { const collabId = makeDocCollabId(existing, 'description') return await this.collaborator.getMarkup(collabId, (existing as GithubPullRequest).description) }, - { url: pullRequestExternal.url } + { url: pullRequestExternal.url }, + { log: true } ) - const update = await this.ctx.withLog( + const update = await this.ctx.with( 'perform pull request diff update', {}, () => @@ -542,7 +546,8 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS account, accountGH ), - { url: pullRequestExternal.url } + { url: pullRequestExternal.url }, + { log: true } ) return { ...update, @@ -950,7 +955,7 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS if (hasFieldsUpdate || body !== undefined) { if (body !== undefined && !isLocked) { - await this.ctx.withLog( + await this.ctx.with( '==> updatePullRequest', {}, async () => { @@ -980,19 +985,23 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS ) } }, - { url: issueExternal.url } + { url: issueExternal.url }, + { log: true } ) issueData.description = await this.provider.getMarkupSafe(container.container, body, this.stripGuestLink) } else if (hasFieldsUpdate) { - await this.ctx.withLog('==> updatePullRequest:', {}, async () => { - this.ctx.info('update-fields', { - url: issueExternal.url, - ...issueUpdate, - workspace: this.provider.getWorkspaceId() - }) - if (isGHWriteAllowed()) { - await okit?.graphql( - ` + await this.ctx.with( + '==> updatePullRequest:', + {}, + async () => { + this.ctx.info('update-fields', { + url: issueExternal.url, + ...issueUpdate, + workspace: this.provider.getWorkspaceId() + }) + if (isGHWriteAllowed()) { + await okit?.graphql( + ` mutation updatePullRequest($issue: ID!) { updatePullRequest(input: { pullRequestId: $issue, @@ -1005,10 +1014,13 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS } } }`, - { issue: issueExternal.id } - ) - } - }) + { issue: issueExternal.id } + ) + } + }, + { issue: issueExternal.id }, + { log: true } + ) } return true } @@ -1266,7 +1278,7 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS } const idsp = idsPart.map((it) => `"${it}"`).join(', ') try { - const response: any = await this.ctx.withLog( + const response: any = await this.ctx.with( 'fetch pull request updates', {}, async () => @@ -1283,7 +1295,8 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS prj: prj.name, repo: repo.name, ids: idsp - } + }, + { log: true } ) const issues: PullRequestExternalData[] = response.nodes diff --git a/services/github/pod-github/src/worker.ts b/services/github/pod-github/src/worker.ts index 4b1d4fee93..2d2a9d55b8 100644 --- a/services/github/pod-github/src/worker.ts +++ b/services/github/pod-github/src/worker.ts @@ -398,22 +398,35 @@ export class GithubWorker implements IntegrationManager { this._client = new TxOperations(this.client, core.account.System) this.liveQuery = new LiveQuery(client) - this.repositoryManager = new RepositorySyncMapper(this.ctx.newChild('repository', {}), this._client, this.app) + this.repositoryManager = new RepositorySyncMapper( + this.ctx.newChild('repository', {}, { span: false }), + this._client, + this.app + ) this.collaborator = createCollaboratorClient(this.workspace.uuid) - this.personMapper = new UsersSyncManager(this.ctx.newChild('users', {}), this._client, this.liveQuery) + this.personMapper = new UsersSyncManager( + this.ctx.newChild('users', {}, { span: false }), + this._client, + this.liveQuery + ) this.mappers = [ { _class: [github.mixin.GithubProject], mapper: this.repositoryManager }, { _class: [tracker.class.Issue], - mapper: new IssueSyncManager(this.ctx.newChild('issue', {}), this._client, this.liveQuery, this.collaborator) + mapper: new IssueSyncManager( + this.ctx.newChild('issue', {}, { span: false }), + this._client, + this.liveQuery, + this.collaborator + ) }, { _class: [github.class.GithubPullRequest], mapper: new PullRequestSyncManager( - this.ctx.newChild('pullRequest', {}), + this.ctx.newChild('pullRequest', {}, { span: false }), this._client, this.liveQuery, this.collaborator @@ -421,7 +434,7 @@ export class GithubWorker implements IntegrationManager { }, { _class: [chunter.class.ChatMessage], - mapper: new CommentSyncManager(this.ctx.newChild('comment', {}), this._client, this.liveQuery) + mapper: new CommentSyncManager(this.ctx.newChild('comment', {}, { span: false }), this._client, this.liveQuery) }, // { // _class: [contact.class.PersonAccount], @@ -429,15 +442,23 @@ export class GithubWorker implements IntegrationManager { // }, { _class: [github.class.GithubReview], - mapper: new ReviewSyncManager(this.ctx.newChild('review', {}), this._client, this.liveQuery) + mapper: new ReviewSyncManager(this.ctx.newChild('review', {}, { span: false }), this._client, this.liveQuery) }, { _class: [github.class.GithubReviewThread], - mapper: new ReviewThreadSyncManager(this.ctx.newChild('review-thread', {}), this._client, this.liveQuery) + mapper: new ReviewThreadSyncManager( + this.ctx.newChild('review-thread', {}, { span: false }), + this._client, + this.liveQuery + ) }, { _class: [github.class.GithubReviewComment], - mapper: new ReviewCommentSyncManager(this.ctx.newChild('review-comment', {}), this._client, this.liveQuery) + mapper: new ReviewCommentSyncManager( + this.ctx.newChild('review-comment', {}, { span: false }), + this._client, + this.liveQuery + ) } ] @@ -1479,7 +1500,7 @@ export class GithubWorker implements IntegrationManager { return } - const docUpdate = await this.ctx.withLog( + const docUpdate = await this.ctx.with( 'sync doc', {}, (ctx) => mapper.sync(existing, info, parent, derivedClient), @@ -1488,7 +1509,8 @@ export class GithubWorker implements IntegrationManager { workspace: this.workspace.uuid, existing: existing !== undefined, objectClass: info.objectClass - } + }, + { log: true } ) if (docUpdate !== undefined) { await derivedClient.update(info, docUpdate) @@ -1571,7 +1593,7 @@ export class GithubWorker implements IntegrationManager { if (this.closing) { break } - await this.ctx.withLog( + await this.ctx.with( 'external sync', {}, async () => { @@ -1666,17 +1688,19 @@ export class GithubWorker implements IntegrationManager { if (this.closing) { break } - await this.ctx.withLog( + await this.ctx.with( 'external sync', { _class: _class.join(', ') }, async () => { await mapper.externalFullSync(integration, derivedClient, _projects, _repositories) }, - { installation: integration.installationName, workspace: this.workspace.uuid } + { installation: integration.installationName, workspace: this.workspace.uuid }, + { log: true } ) } }, - { installation: integration.installationName, workspace: this.workspace.uuid } + { installation: integration.installationName, workspace: this.workspace.uuid }, + { log: true } ) } } diff --git a/services/gmail/pod-gmail/src/__tests__/attachments.test.ts b/services/gmail/pod-gmail/src/__tests__/attachments.test.ts index 34983df25d..839223e5e7 100644 --- a/services/gmail/pod-gmail/src/__tests__/attachments.test.ts +++ b/services/gmail/pod-gmail/src/__tests__/attachments.test.ts @@ -27,7 +27,6 @@ describe('AttachmentHandler', () => { newChild: jest.fn(), with: jest.fn(), withSync: jest.fn(), - withLog: jest.fn(), logger: { info: jest.fn(), error: jest.fn(),