From f9089004e2fc95f4f6676c0340c1834c6e7a5b76 Mon Sep 17 00:00:00 2001 From: Josh Wulf Date: Tue, 26 Mar 2024 10:08:04 +1300 Subject: [PATCH] feat(repo): add enhanced debug output for http errors closes #87 --- README.md | 20 ++++++++++++++++++-- src/admin/lib/AdminApiClient.ts | 19 +++++++++++++++---- src/lib/jest.globalSetup.ts | 14 ++++++++++---- src/modeler/lib/ModelerAPIClient.ts | 19 ++++++++++++++++++- src/oauth/lib/NullAuthProvider.ts | 2 +- src/operate/lib/OperateApiClient.ts | 21 +++++++++++++++++++++ src/optimize/lib/OptimizeApiClient.ts | 21 ++++++++++++++++----- src/tasklist/lib/TasklistApiClient.ts | 20 +++++++++++++++++++- src/zeebe/lib/GrpcClient.ts | 2 +- src/zeebe/lib/ZBWorkerBase.ts | 2 +- src/zeebe/zb/ZeebeGrpcClient.ts | 2 +- 11 files changed, 121 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index de15bc49..6c3df64e 100644 --- a/README.md +++ b/README.md @@ -127,7 +127,7 @@ CAMUNDA_TOKEN_SCOPE Here is an example of doing this via the constructor, rather than via the environment: -````typescript +```typescript import { Camunda8 } from '@camunda8/sdk' const c8 = new Camunda8({ @@ -168,4 +168,20 @@ export CAMUNDA_CONSOLE_CLIENT_ID='e-JdgKfJy9hHSXzi' export CAMUNDA_CONSOLE_CLIENT_SECRET='DT8Pe-ANC6e3Je_ptLyzZvBNS0aFwaIV' export CAMUNDA_CONSOLE_BASE_URL='https://api.cloud.camunda.io' export CAMUNDA_CONSOLE_OAUTH_AUDIENCE='api.cloud.camunda.io' -```` +``` + +## Debugging + +The SDK uses the [`debug`](https://github.com/debug-js/debug) library. To enable debugging output, set a value for the `DEBUG` environment variable. The value is a comma-separated list of debugging namespaces. The SDK has the following namespaces: + +| Value | Component | +| ---------------------- | -------------------- | +| `camunda:adminconsole` | Admin Console API | +| `camunda:modeler` | Modeler API | +| `camunda:operate` | Operate API | +| `camunda:optimize` | Optimize API | +| `camunda:tasklist` | Tasklist API | +| `camunda:oauth` | OAuth Token Exchange | +| `camunda:grpc` | Zeebe gRPC channel | +| `camunda:worker` | Zeebe Worker | +| `camunda:zeebeclient` | Zeebe Client | diff --git a/src/admin/lib/AdminApiClient.ts b/src/admin/lib/AdminApiClient.ts index b8b3980f..602ebada 100644 --- a/src/admin/lib/AdminApiClient.ts +++ b/src/admin/lib/AdminApiClient.ts @@ -14,7 +14,7 @@ import { IOAuthProvider } from '../../oauth' import * as Dto from './AdminDto' -const debug = d('consoleapi') +const debug = d('camunda:adminconsole') export class AdminApiClient { private userAgentString: string @@ -45,9 +45,20 @@ export class AdminApiClient { certificateAuthority, }, hooks: { - beforeRequest: [ - (options: unknown) => { - debug('beforeRequest', options) + beforeError: [ + (error) => { + const { request } = error + if (request) { + console.error(`Error in request to ${request.options.url.href}`) + console.error( + `Request headers: ${JSON.stringify(request.options.headers)}` + ) + console.error(`Error: ${error.code} - ${error.message}`) + + // Attach more contextual information to the error object + error.message += ` (request to ${request.options.url.href})` + } + return error }, ], }, diff --git a/src/lib/jest.globalSetup.ts b/src/lib/jest.globalSetup.ts index d581ac77..4c04ae86 100644 --- a/src/lib/jest.globalSetup.ts +++ b/src/lib/jest.globalSetup.ts @@ -23,22 +23,28 @@ export default async () => { const bpmn = BpmnParser.parseBpmn(files) // eslint-disable-next-line @typescript-eslint/no-explicit-any const processIds = (bpmn as any[]).map( - (b) => b['bpmn:definitions']?.['bpmn:process']?.['@_id'] + (b) => b?.['bpmn:definitions']?.['bpmn:process']?.['@_id'] ) const operate = new OperateApiClient() - const zeebe = new ZeebeGrpcClient() + const zeebe = new ZeebeGrpcClient({ + config: { + zeebeGrpcSettings: { ZEEBE_CLIENT_LOG_LEVEL: 'NONE' }, + }, + }) for (const id of processIds) { if (id) { const res = await operate.searchProcessInstances({ filter: { bpmnProcessId: id, state: 'ACTIVE' }, }) const instancesKeys = res.items.map((instance) => instance.key) - console.log(`Canceling ${instancesKeys.length} instances for ${id}`) + if (instancesKeys.length > 0) { + console.log(`Cancelling ${instancesKeys.length} instances for ${id}`) + } for (const key of instancesKeys) { try { await zeebe.cancelProcessInstance(key) } catch (e) { - console.log('Error canceling process instance', key) + console.log('Error cancelling process instance', key) console.log(e) } } diff --git a/src/modeler/lib/ModelerAPIClient.ts b/src/modeler/lib/ModelerAPIClient.ts index 76a7732c..cccdc735 100644 --- a/src/modeler/lib/ModelerAPIClient.ts +++ b/src/modeler/lib/ModelerAPIClient.ts @@ -12,7 +12,7 @@ import { IOAuthProvider } from 'oauth' import * as Dto from './ModelerDto' -const debug = d('modelerapi') +const debug = d('camunda:modeler') const API_VERSION = 'v1' @@ -43,6 +43,23 @@ export class ModelerApiClient { certificateAuthority, }, responseType: 'json', + hooks: { + beforeError: [ + (error) => { + const { request } = error + if (request) { + debug(`Error in request to ${request.options.url.href}`) + debug( + `Request headers: ${JSON.stringify(request.options.headers)}` + ) + debug(`Error: ${error.code} - ${error.message}`) + // Attach more contextual information to the error object + error.message += ` (request to ${request.options.url.href})` + } + return error + }, + ], + }, }) debug(`baseUrl: ${prefixUrl}`) } diff --git a/src/oauth/lib/NullAuthProvider.ts b/src/oauth/lib/NullAuthProvider.ts index 6a30e00a..eb089bfd 100644 --- a/src/oauth/lib/NullAuthProvider.ts +++ b/src/oauth/lib/NullAuthProvider.ts @@ -3,7 +3,7 @@ import { IOAuthProvider } from 'oauth' import { TokenGrantAudienceType } from './IOAuthProvider' -const d = debug('oauth') +const d = debug('camunda:oauth') export class NullAuthProvider implements IOAuthProvider { public async getToken(audience: TokenGrantAudienceType): Promise { diff --git a/src/operate/lib/OperateApiClient.ts b/src/operate/lib/OperateApiClient.ts index 3a0506fe..977a54e3 100644 --- a/src/operate/lib/OperateApiClient.ts +++ b/src/operate/lib/OperateApiClient.ts @@ -1,3 +1,4 @@ +import { debug as d } from 'debug' import got from 'got' import { CamundaEnvironmentConfigurator, @@ -30,6 +31,8 @@ import { parseSearchResults } from './parseSearchResults' const OPERATE_API_VERSION = 'v1' +const debug = d('camunda:operate') + type JSONDoc = { [key: string]: string | boolean | number | JSONDoc } type EnhanceWithTenantIdIfMissing = T extends { filter: { tenantId: string | undefined } @@ -91,6 +94,24 @@ export class OperateApiClient { https: { certificateAuthority, }, + hooks: { + beforeError: [ + (error) => { + const { request } = error + if (request) { + debug(`Error in request to ${request.options.url.href}`) + debug( + `Request headers: ${JSON.stringify(request.options.headers)}` + ) + debug(`Error: ${error.code} - ${error.message}`) + + // Attach more contextual information to the error object + error.message += ` (request to ${request.options.url.href})` + } + return error + }, + ], + }, }) this.tenantId = config.CAMUNDA_TENANT_ID } diff --git a/src/optimize/lib/OptimizeApiClient.ts b/src/optimize/lib/OptimizeApiClient.ts index 14b63c39..4ab57403 100644 --- a/src/optimize/lib/OptimizeApiClient.ts +++ b/src/optimize/lib/OptimizeApiClient.ts @@ -1,4 +1,4 @@ -import d from 'debug' +import { debug as d } from 'debug' import got from 'got' import { CamundaEnvironmentConfigurator, @@ -23,7 +23,7 @@ import { } from './APIObjects' import { ReportResults } from './ReportResults' -const debug = d('optimizeapi') +const debug = d('camunda:optimize') /** * @description The high-level API client for Optimize. @@ -76,9 +76,20 @@ export class OptimizeApiClient { certificateAuthority, }, hooks: { - beforeRequest: [ - (options: unknown) => { - debug('beforeRequest', options) + beforeError: [ + (error) => { + const { request } = error + if (request) { + console.error(`Error in request to ${request.options.url.href}`) + debug( + `Request headers: ${JSON.stringify(request.options.headers)}` + ) + console.error(`Error: ${error.code} - ${error.message}`) + + // Attach more contextual information to the error object + error.message += ` (request to ${request.options.url.href})` + } + return error }, ], }, diff --git a/src/tasklist/lib/TasklistApiClient.ts b/src/tasklist/lib/TasklistApiClient.ts index f0331f8c..655d9c71 100644 --- a/src/tasklist/lib/TasklistApiClient.ts +++ b/src/tasklist/lib/TasklistApiClient.ts @@ -29,7 +29,7 @@ import { } from './TasklistDto' import { JSONDoc, encodeTaskVariablesForAPIRequest } from './utils' -const trace = debug('tasklist:rest') +const trace = debug('camunda:tasklist') const TASKLIST_API_VERSION = 'v1' @@ -77,6 +77,24 @@ export class TasklistApiClient { https: { certificateAuthority, }, + hooks: { + beforeError: [ + (error) => { + const { request } = error + if (request) { + console.error(`Error in request to ${request.options.url.href}`) + console.error( + `Request headers: ${JSON.stringify(request.options.headers)}` + ) + console.error(`Error: ${error.code} - ${error.message}`) + + // Attach more contextual information to the error object + error.message += ` (request to ${request.options.url.href})` + } + return error + }, + ], + }, }) trace(`prefixUrl: ${prefixUrl}`) } diff --git a/src/zeebe/lib/GrpcClient.ts b/src/zeebe/lib/GrpcClient.ts index effd6084..ebd09250 100644 --- a/src/zeebe/lib/GrpcClient.ts +++ b/src/zeebe/lib/GrpcClient.ts @@ -19,7 +19,7 @@ import { packageVersion } from './GetPackageVersion' import { GrpcError } from './GrpcError' import { Loglevel, ZBCustomLogger } from './interfaces-published-contract' -const debug = d('grpc') +const debug = d('camunda:grpc') export interface GrpcClientExtendedOptions { longPoll?: MaybeTimeDuration diff --git a/src/zeebe/lib/ZBWorkerBase.ts b/src/zeebe/lib/ZBWorkerBase.ts index 41132b24..a927e9d9 100644 --- a/src/zeebe/lib/ZBWorkerBase.ts +++ b/src/zeebe/lib/ZBWorkerBase.ts @@ -24,7 +24,7 @@ import { ZBClientOptions } from './interfaces-published-contract' import { parseVariablesAndCustomHeadersToJSON } from '.' -const debug = d('worker') +const debug = d('camunda:worker') debug('Loaded ZBWorkerBase') const MIN_ACTIVE_JOBS_RATIO_BEFORE_ACTIVATING_JOBS = 0.3 diff --git a/src/zeebe/zb/ZeebeGrpcClient.ts b/src/zeebe/zb/ZeebeGrpcClient.ts index 5cd51aab..c8c0b5c4 100644 --- a/src/zeebe/zb/ZeebeGrpcClient.ts +++ b/src/zeebe/zb/ZeebeGrpcClient.ts @@ -42,7 +42,7 @@ import { Utils } from '../lib/utils' import { ZBBatchWorker } from './ZBBatchWorker' import { ZBWorker } from './ZBWorker' -const debug = d('client') +const debug = d('camunda:zeebeclient') const idColors = [ chalk.yellow,