Skip to content

Commit c126990

Browse files
committed
Improve structured logging with proper fields and messages
Add missing structured fields to log calls while preserving human-readable messages with interpolated values. This makes logs both machine-parseable and human-friendly. Changes: - Add jobId, executionId, path fields to job operations - Add cartridgeName, codeVersionId fields to code operations - Add method, url fields to client logging - Add headerName, keyPreview, username, port fields to auth - Change reserved 'hostname' field to 'server' in watch.ts
1 parent f6b4b2d commit c126990

File tree

10 files changed

+64
-66
lines changed

10 files changed

+64
-66
lines changed

packages/b2c-tooling-sdk/src/auth/api-key.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export class ApiKeyStrategy implements AuthStrategy {
3737

3838
// Show partial key for identification (first 8 chars)
3939
const keyPreview = key.length > 8 ? `${key.slice(0, 8)}...` : key;
40-
logger.debug({headerName}, `[Auth] Using API Key authentication (${headerName}): ${keyPreview}`);
40+
logger.debug({headerName, keyPreview}, `[Auth] Using API Key authentication (${headerName}): ${keyPreview}`);
4141
}
4242

4343
async fetch(url: string, init: RequestInit = {}): Promise<Response> {

packages/b2c-tooling-sdk/src/auth/oauth-implicit.ts

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -107,20 +107,17 @@ export class ImplicitOAuthStrategy implements AuthStrategy {
107107

108108
const logger = getLogger();
109109
logger.debug(
110-
{clientId: this.config.clientId, accountManagerHost: this.accountManagerHost, localPort: this.localPort},
111-
`[Auth] ImplicitOAuthStrategy initialized for client: ${this.config.clientId}`,
112-
);
113-
logger.trace(
114-
{scopes: this.config.scopes},
115-
`[Auth] Configured scopes: ${this.config.scopes?.join(', ') || '(none)'}`,
110+
{clientId: this.config.clientId, accountManagerHost: this.accountManagerHost, port: this.localPort},
111+
'[Auth] ImplicitOAuthStrategy initialized',
116112
);
113+
logger.trace({scopes: this.config.scopes}, '[Auth] Configured scopes');
117114
}
118115

119116
async fetch(url: string, init: RequestInit = {}): Promise<Response> {
120117
const logger = getLogger();
121118
const method = init.method || 'GET';
122119

123-
logger.trace({method, url}, `[Auth] Fetching with implicit OAuth: ${method} ${url}`);
120+
logger.trace({method, url}, '[Auth] Fetching with implicit OAuth');
124121

125122
const token = await this.getAccessToken();
126123

@@ -132,10 +129,7 @@ export class ImplicitOAuthStrategy implements AuthStrategy {
132129
let res = await fetch(url, {...init, headers});
133130
const duration = Date.now() - startTime;
134131

135-
logger.debug(
136-
{method, url, status: res.status, duration},
137-
`[Auth] Response: ${method} ${url} ${res.status} ${duration}ms`,
138-
);
132+
logger.debug({method, url, status: res.status, duration}, '[Auth] Response');
139133

140134
// RESILIENCE: If the server says 401, the token might have expired or been revoked.
141135
// We retry exactly once after invalidating the cached token.
@@ -149,10 +143,7 @@ export class ImplicitOAuthStrategy implements AuthStrategy {
149143
res = await fetch(url, {...init, headers});
150144
const retryDuration = Date.now() - retryStart;
151145

152-
logger.debug(
153-
{method, url, status: res.status, duration: retryDuration},
154-
`[Auth] Retry response: ${method} ${url} ${res.status} ${retryDuration}ms`,
155-
);
146+
logger.debug({method, url, status: res.status, duration: retryDuration}, '[Auth] Retry response');
156147
}
157148

158149
return res;
@@ -244,10 +235,7 @@ export class ImplicitOAuthStrategy implements AuthStrategy {
244235
);
245236
ACCESS_TOKEN_CACHE.delete(clientId);
246237
} else {
247-
logger.debug(
248-
{timeUntilExpiryMs: timeUntilExpiry},
249-
`[Auth] Reusing cached access token (expires in ${Math.round(timeUntilExpiry / 1000)}s)`,
250-
);
238+
logger.debug({timeUntilExpiryMs: timeUntilExpiry}, '[Auth] Reusing cached access token');
251239
return cached.accessToken;
252240
}
253241
}
@@ -314,7 +302,7 @@ export class ImplicitOAuthStrategy implements AuthStrategy {
314302
logger.trace({authorizeUrl}, '[Auth] Authorization URL');
315303

316304
// Print URL to console (in case machine has no default browser)
317-
logger.info(`Login URL: ${authorizeUrl}`);
305+
logger.info({url: authorizeUrl}, `Login URL: ${authorizeUrl}`);
318306
logger.info('If the URL does not open automatically, copy/paste it into a browser on this machine.');
319307

320308
// Attempt to open the browser
@@ -337,7 +325,7 @@ export class ImplicitOAuthStrategy implements AuthStrategy {
337325
hasAccessToken: !!accessToken,
338326
hasError: !!error,
339327
},
340-
`[Auth] Received redirect request: ${requestUrl.pathname}`,
328+
'[Auth] Received redirect request',
341329
);
342330

343331
if (!accessToken && !error) {
@@ -349,7 +337,7 @@ export class ImplicitOAuthStrategy implements AuthStrategy {
349337
} else if (accessToken) {
350338
const authDuration = Date.now() - startTime;
351339
// Successfully received access token
352-
logger.debug({authDurationMs: authDuration}, `[Auth] Got access token response (took ${authDuration}ms)`);
340+
logger.debug({duration: authDuration}, `[Auth] Got access token response (${authDuration}ms)`);
353341
logger.info('Successfully authenticated');
354342

355343
try {
@@ -366,7 +354,7 @@ export class ImplicitOAuthStrategy implements AuthStrategy {
366354

367355
logger.debug(
368356
{expiresIn, expiresAt: expiration.toISOString(), scopes},
369-
`[Auth] Token expires in ${expiresIn}s, scopes: ${scopes.join(', ') || '(none)'}`,
357+
`[Auth] Token expires in ${expiresIn}s, scopes: ${scopes.join(' ')}`,
370358
);
371359

372360
resolve({
@@ -391,7 +379,7 @@ export class ImplicitOAuthStrategy implements AuthStrategy {
391379
} else if (error) {
392380
// OAuth error response
393381
const errorMessage = errorDescription || error;
394-
logger.error({error, errorDescription}, `[Auth] OAuth error: ${errorMessage}`);
382+
logger.error({error, errorDescription}, `[Auth] OAuth error: ${error}`);
395383
response.writeHead(500, {'Content-Type': 'text/plain'});
396384
response.write(`Authentication failed: ${errorMessage}`);
397385
response.end();
@@ -421,7 +409,7 @@ export class ImplicitOAuthStrategy implements AuthStrategy {
421409
});
422410

423411
server.on('error', (err) => {
424-
logger.error({error: err.message, port: this.localPort}, `[Auth] Failed to start OAuth redirect server`);
412+
logger.error({error: err.message, port: this.localPort}, '[Auth] Failed to start OAuth redirect server');
425413
reject(new Error(`Failed to start OAuth redirect server: ${err.message}`));
426414
});
427415
});

packages/b2c-tooling-sdk/src/auth/oauth.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ export class OAuthStrategy implements AuthStrategy {
178178
logger.debug({method, url}, `[Auth REQ] ${method} ${url}`);
179179

180180
// Trace: Log request details
181-
logger.trace({headers: requestHeaders, body: params.toString()}, `[Auth REQ BODY] ${method} ${url}`);
181+
logger.trace({method, url, headers: requestHeaders, body: params.toString()}, `[Auth REQ BODY] ${method} ${url}`);
182182

183183
const startTime = Date.now();
184184
const response = await fetch(url, {
@@ -202,7 +202,7 @@ export class OAuthStrategy implements AuthStrategy {
202202

203203
if (!response.ok) {
204204
const errorText = await response.text();
205-
logger.trace({headers: responseHeaders, body: errorText}, `[Auth RESP BODY] ${method} ${url}`);
205+
logger.trace({method, url, headers: responseHeaders, body: errorText}, `[Auth RESP BODY] ${method} ${url}`);
206206
throw new Error(`Failed to get access token: ${response.status} ${response.statusText} - ${errorText}`);
207207
}
208208

@@ -213,7 +213,7 @@ export class OAuthStrategy implements AuthStrategy {
213213
};
214214

215215
// Trace: Log response details
216-
logger.trace({headers: responseHeaders, body: data}, `[Auth RESP BODY] ${method} ${url}`);
216+
logger.trace({method, url, headers: responseHeaders, body: data}, `[Auth RESP BODY] ${method} ${url}`);
217217

218218
const jwt = decodeJWT(data.access_token);
219219
logger.trace({jwt: jwt.payload}, '[Auth] JWT payload');

packages/b2c-tooling-sdk/src/clients/middleware.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ export function createLoggingMiddleware(config?: string | LoggingMiddlewareConfi
143143
// Mask sensitive/large body keys before logging
144144
const maskedBody = maskBody(body, maskBodyKeys);
145145
logger.trace(
146-
{headers: headersToObject(request.headers), body: maskedBody},
146+
{method: request.method, url, headers: headersToObject(request.headers), body: maskedBody},
147147
`${reqTag} ${request.method} ${url} body`,
148148
);
149149

@@ -178,7 +178,7 @@ export function createLoggingMiddleware(config?: string | LoggingMiddlewareConfi
178178
// Mask sensitive/large body keys before logging
179179
const maskedResponseBody = maskBody(responseBody, maskBodyKeys);
180180
logger.trace(
181-
{headers: headersToObject(response.headers), body: maskedResponseBody},
181+
{method: request.method, url, headers: headersToObject(response.headers), body: maskedResponseBody},
182182
`${respTag} ${request.method} ${url} body`,
183183
);
184184

packages/b2c-tooling-sdk/src/clients/webdav.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,12 @@ export class WebDavClient {
143143

144144
// Trace: Log request details
145145
logger.trace(
146-
{headers: this.headersToObject(request.headers), body: this.formatBody(init?.body)},
146+
{
147+
method: request.method,
148+
url: request.url,
149+
headers: this.headersToObject(request.headers),
150+
body: this.formatBody(init?.body),
151+
},
147152
`[WebDAV REQ BODY] ${request.method} ${request.url}`,
148153
);
149154

@@ -188,7 +193,10 @@ export class WebDavClient {
188193
const clonedResponse = response.clone();
189194
responseBody = await clonedResponse.text();
190195
}
191-
logger.trace({headers: responseHeaders, body: responseBody}, `[WebDAV RESP BODY] ${request.method} ${request.url}`);
196+
logger.trace(
197+
{method: request.method, url: request.url, headers: responseHeaders, body: responseBody},
198+
`[WebDAV RESP BODY] ${request.method} ${request.url}`,
199+
);
192200

193201
return response;
194202
}

packages/b2c-tooling-sdk/src/operations/code/deploy.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,10 @@ export async function deleteCartridges(instance: B2CInstance, cartridges: Cartri
9292
const cartridgePath = `Cartridges/${codeVersion}/${c.dest}`;
9393
try {
9494
await webdav.delete(cartridgePath);
95-
logger.debug({cartridge: c.dest}, `Deleted ${cartridgePath}`);
95+
logger.debug({cartridgeName: c.dest, path: cartridgePath}, `Deleted ${cartridgePath}`);
9696
} catch {
9797
// Ignore errors - cartridge may not exist
98-
logger.debug({cartridge: c.dest}, `Could not delete ${cartridgePath} (may not exist)`);
98+
logger.debug({cartridgeName: c.dest, path: cartridgePath}, `Could not delete ${cartridgePath} (may not exist)`);
9999
}
100100
}
101101
}
@@ -243,7 +243,7 @@ export async function findAndDeployCartridges(
243243

244244
logger.debug({count: cartridges.length}, `Found ${cartridges.length} cartridge(s)`);
245245
for (const c of cartridges) {
246-
logger.debug({cartridge: c.name, path: c.src}, ` ${c.name}`);
246+
logger.debug({cartridgeName: c.name, path: c.src}, ` ${c.name}`);
247247
}
248248

249249
// Optionally delete existing cartridges first

packages/b2c-tooling-sdk/src/operations/code/versions.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ export async function reloadCodeVersion(instance: B2CInstance, codeVersionId?: s
116116
throw new Error('No code version specified and no active version found');
117117
}
118118

119-
logger.debug({targetVersion}, `Reloading code version ${targetVersion}`);
119+
logger.debug({codeVersionId: targetVersion}, `Reloading code version ${targetVersion}`);
120120

121121
// If the target is already active, we need to toggle to another version first
122122
if (activeVersion?.id === targetVersion) {
@@ -125,13 +125,13 @@ export async function reloadCodeVersion(instance: B2CInstance, codeVersionId?: s
125125
throw new Error('Cannot reload: no alternate code version available for toggle');
126126
}
127127

128-
logger.debug({alternateVersion: alternateVersion.id}, `Temporarily activating ${alternateVersion.id}`);
128+
logger.debug({codeVersionId: alternateVersion.id}, `Temporarily activating ${alternateVersion.id}`);
129129
await activateCodeVersion(instance, alternateVersion.id!);
130130
}
131131

132132
// Now activate the target version
133133
await activateCodeVersion(instance, targetVersion);
134-
logger.debug({targetVersion}, `Code version ${targetVersion} reloaded`);
134+
logger.debug({codeVersionId: targetVersion}, `Code version ${targetVersion} reloaded`);
135135
}
136136

137137
/**

packages/b2c-tooling-sdk/src/operations/code/watch.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ export async function watchCartridges(
145145

146146
logger.debug({count: cartridges.length}, `Watching ${cartridges.length} cartridge(s)`);
147147
for (const c of cartridges) {
148-
logger.info({cartridge: c.name, path: c.src}, ` ${c.name}`);
148+
logger.info({cartridgeName: c.name, path: c.src}, ` ${c.name}`);
149149
}
150150

151151
const webdav = instance.webdav;
@@ -229,7 +229,7 @@ export async function watchCartridges(
229229
await webdav.delete(uploadPath);
230230

231231
logger.debug(
232-
{fileCount: validUploadFiles.length, hostname: instance.config.hostname},
232+
{fileCount: validUploadFiles.length, server: instance.config.hostname},
233233
`Uploaded ${validUploadFiles.length} file(s)`,
234234
);
235235

@@ -253,9 +253,9 @@ export async function watchCartridges(
253253
const deletePath = `${webdavLocation}/${f.dest}`;
254254
try {
255255
await webdav.delete(deletePath);
256-
logger.info({file: deletePath}, `Deleted: ${deletePath}`);
256+
logger.info({path: deletePath}, `Deleted: ${deletePath}`);
257257
} catch (error) {
258-
logger.debug({file: deletePath, error}, `Failed to delete ${deletePath}`);
258+
logger.debug({path: deletePath, error}, `Failed to delete ${deletePath}`);
259259
}
260260
}
261261

@@ -291,7 +291,7 @@ export async function watchCartridges(
291291
options.onError?.(error);
292292
});
293293

294-
logger.debug({hostname: instance.config.hostname, codeVersion}, 'Watching for changes...');
294+
logger.debug({server: instance.config.hostname, codeVersion}, 'Watching for changes...');
295295

296296
return {
297297
watcher,

packages/b2c-tooling-sdk/src/operations/jobs/run.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,12 @@ export async function executeJob(
117117
const errorBody = await response.text().catch(() => '');
118118
if (errorBody.includes('JobAlreadyRunningException')) {
119119
if (waitForRunning) {
120-
logger.warn(`Job ${jobId} already running, waiting for it to finish...`);
120+
logger.warn({jobId}, `Job ${jobId} already running, waiting for it to finish...`);
121121

122122
// Search for the running execution
123123
const runningExecution = await findRunningJobExecution(instance, jobId);
124124
if (runningExecution) {
125-
logger.debug({executionId: runningExecution.id}, `Found running execution ${runningExecution.id}`);
125+
logger.debug({jobId, executionId: runningExecution.id}, `Found running execution ${runningExecution.id}`);
126126
await waitForJob(instance, jobId, runningExecution.id!);
127127
// Retry execution after the running job finishes
128128
return executeJob(instance, jobId, {...options, waitForRunning: false});
@@ -139,7 +139,7 @@ export async function executeJob(
139139
throw new Error(message);
140140
}
141141

142-
logger.debug({executionId: data.id, status: data.execution_status}, `Job ${jobId} started: ${data.id}`);
142+
logger.debug({jobId, executionId: data.id, status: data.execution_status}, `Job ${jobId} started: ${data.id}`);
143143

144144
return data;
145145
}
@@ -231,14 +231,14 @@ export async function waitForJob(
231231

232232
// Check for terminal states
233233
if (execution.execution_status === 'aborted' || execution.exit_status?.code === 'ERROR') {
234-
logger.debug({execution}, `Job ${jobId} failed`);
234+
logger.debug({jobId, executionId, execution}, `Job ${jobId} failed`);
235235
throw new JobExecutionError(`Job ${jobId} failed`, execution);
236236
}
237237

238238
if (execution.execution_status === 'finished') {
239239
const durationSec = (execution.duration ?? 0) / 1000;
240240
logger.debug(
241-
{executionId, status: execution.exit_status?.code, duration: durationSec},
241+
{jobId, executionId, status: execution.exit_status?.code, duration: durationSec},
242242
`Job ${jobId} finished. Status: ${execution.exit_status?.code} (duration: ${durationSec}s)`,
243243
);
244244
return execution;
@@ -247,7 +247,7 @@ export async function waitForJob(
247247
// Log periodic updates
248248
if (ticks % 5 === 0) {
249249
logger.debug(
250-
{executionId, status: execution.execution_status, elapsed: elapsed / 1000},
250+
{jobId, executionId, status: execution.execution_status, elapsed: elapsed / 1000},
251251
`Waiting for job ${jobId} to finish (${(elapsed / 1000).toFixed(0)}s elapsed)...`,
252252
);
253253
}

0 commit comments

Comments
 (0)