@outfitter/logging 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -184,6 +184,7 @@ Routes logs to stdout/stderr based on level:
184
184
 
185
185
  - `trace`, `debug`, `info` -> stdout
186
186
  - `warn`, `error`, `fatal` -> stderr
187
+ - Falls back to `console.*` when process streams are unavailable (edge/serverless)
187
188
 
188
189
  ```typescript
189
190
  import { createConsoleSink } from "@outfitter/logging";
package/dist/index.d.ts CHANGED
@@ -1,4 +1,12 @@
1
1
  /**
2
+ * @outfitter/logging
3
+ *
4
+ * Structured logging via logtape with automatic sensitive data redaction.
5
+ * Provides consistent log formatting across CLI, MCP, and server contexts.
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+ /**
2
10
  * Log levels supported by the logger, ordered from lowest to highest severity.
3
11
  *
4
12
  * Level priority (lowest to highest): trace (0) < debug (1) < info (2) < warn (3) < error (4) < fatal (5)
@@ -208,36 +216,42 @@ interface LoggerInstance {
208
216
  * @param metadata - Optional structured metadata
209
217
  */
210
218
  trace(message: string, metadata?: Record<string, unknown>): void;
219
+ trace(metadata: Record<string, unknown>, message: string): never;
211
220
  /**
212
221
  * Log at debug level (development debugging).
213
222
  * @param message - Human-readable log message
214
223
  * @param metadata - Optional structured metadata
215
224
  */
216
225
  debug(message: string, metadata?: Record<string, unknown>): void;
226
+ debug(metadata: Record<string, unknown>, message: string): never;
217
227
  /**
218
228
  * Log at info level (normal operations).
219
229
  * @param message - Human-readable log message
220
230
  * @param metadata - Optional structured metadata
221
231
  */
222
232
  info(message: string, metadata?: Record<string, unknown>): void;
233
+ info(metadata: Record<string, unknown>, message: string): never;
223
234
  /**
224
235
  * Log at warn level (unexpected but handled situations).
225
236
  * @param message - Human-readable log message
226
237
  * @param metadata - Optional structured metadata
227
238
  */
228
239
  warn(message: string, metadata?: Record<string, unknown>): void;
240
+ warn(metadata: Record<string, unknown>, message: string): never;
229
241
  /**
230
242
  * Log at error level (failures requiring attention).
231
243
  * @param message - Human-readable log message
232
244
  * @param metadata - Optional structured metadata
233
245
  */
234
246
  error(message: string, metadata?: Record<string, unknown>): void;
247
+ error(metadata: Record<string, unknown>, message: string): never;
235
248
  /**
236
249
  * Log at fatal level (unrecoverable failures).
237
250
  * @param message - Human-readable log message
238
251
  * @param metadata - Optional structured metadata
239
252
  */
240
253
  fatal(message: string, metadata?: Record<string, unknown>): void;
254
+ fatal(metadata: Record<string, unknown>, message: string): never;
241
255
  /**
242
256
  * Get the current context metadata attached to this logger.
243
257
  * @returns Copy of the logger's context object
@@ -353,7 +367,7 @@ interface FileSinkOptions {
353
367
  /** Absolute path to the log file */
354
368
  path: string;
355
369
  /**
356
- * Append to existing file or truncate on start.
370
+ * Append to existing file or truncate before the first write.
357
371
  * @defaultValue true
358
372
  */
359
373
  append?: boolean;
@@ -471,8 +485,8 @@ declare function createJsonFormatter(): Formatter;
471
485
  */
472
486
  declare function createPrettyFormatter(options?: PrettyFormatterOptions): Formatter;
473
487
  /**
474
- * Create a console sink that writes to stdout/stderr.
475
- * Info and below go to stdout, warn and above go to stderr.
488
+ * Create a console sink that writes via console methods.
489
+ * Info and below go to console.info/debug, warn and above go to console.warn/error.
476
490
  *
477
491
  * @param options - Console sink options
478
492
  * @returns Sink configured for console output
package/dist/index.js CHANGED
@@ -1,5 +1,4 @@
1
1
  // src/index.ts
2
- import { writeFileSync } from "node:fs";
3
2
  var LEVEL_PRIORITY = {
4
3
  trace: 0,
5
4
  debug: 1,
@@ -215,12 +214,30 @@ function createChildLogger(parent, context) {
215
214
  const parentContext = parent.getContext();
216
215
  const mergedContext = { ...parentContext, ...context };
217
216
  const childLogger = {
218
- trace: (message, metadata) => parent.trace(message, { ...context, ...metadata }),
219
- debug: (message, metadata) => parent.debug(message, { ...context, ...metadata }),
220
- info: (message, metadata) => parent.info(message, { ...context, ...metadata }),
221
- warn: (message, metadata) => parent.warn(message, { ...context, ...metadata }),
222
- error: (message, metadata) => parent.error(message, { ...context, ...metadata }),
223
- fatal: (message, metadata) => parent.fatal(message, { ...context, ...metadata }),
217
+ trace: (message, metadata) => parent.trace(message, {
218
+ ...context,
219
+ ...metadata
220
+ }),
221
+ debug: (message, metadata) => parent.debug(message, {
222
+ ...context,
223
+ ...metadata
224
+ }),
225
+ info: (message, metadata) => parent.info(message, {
226
+ ...context,
227
+ ...metadata
228
+ }),
229
+ warn: (message, metadata) => parent.warn(message, {
230
+ ...context,
231
+ ...metadata
232
+ }),
233
+ error: (message, metadata) => parent.error(message, {
234
+ ...context,
235
+ ...metadata
236
+ }),
237
+ fatal: (message, metadata) => parent.fatal(message, {
238
+ ...context,
239
+ ...metadata
240
+ }),
224
241
  getContext: () => mergedContext,
225
242
  setLevel: (level) => parent.setLevel(level),
226
243
  addSink: (sink) => parent.addSink(sink),
@@ -287,20 +304,28 @@ function createPrettyFormatter(options) {
287
304
  };
288
305
  }
289
306
  function createConsoleSink(options) {
290
- const useColors = options?.colors ?? process.stdout.isTTY ?? false;
307
+ const useColors = options?.colors ?? (typeof process !== "undefined" ? Boolean(process.stdout?.isTTY) : false);
291
308
  const formatter = createPrettyFormatter({ colors: useColors });
292
309
  const sink = {
293
310
  formatter,
294
311
  write(record, formatted) {
295
312
  const output = formatted ?? formatter.format(record);
296
- const outputWithNewline = output.endsWith(`
297
- `) ? output : `${output}
298
- `;
299
- if (LEVEL_PRIORITY[record.level] >= LEVEL_PRIORITY.warn) {
300
- process.stderr.write(outputWithNewline);
301
- } else {
302
- process.stdout.write(outputWithNewline);
313
+ const outputLine = output.endsWith(`
314
+ `) ? output.slice(0, -1) : output;
315
+ const runtimeConsole = globalThis["console"];
316
+ if (record.level === "fatal" || record.level === "error") {
317
+ runtimeConsole.error(outputLine);
318
+ return;
303
319
  }
320
+ if (record.level === "warn") {
321
+ runtimeConsole.warn(outputLine);
322
+ return;
323
+ }
324
+ if (record.level === "debug" || record.level === "trace") {
325
+ runtimeConsole.debug(outputLine);
326
+ return;
327
+ }
328
+ runtimeConsole.info(outputLine);
304
329
  }
305
330
  };
306
331
  registeredSinks.add(sink);
@@ -311,9 +336,7 @@ function createFileSink(options) {
311
336
  const buffer = [];
312
337
  const { path } = options;
313
338
  const append = options.append ?? true;
314
- if (!append) {
315
- writeFileSync(path, "");
316
- }
339
+ let cachedContent = append ? null : "";
317
340
  const sink = {
318
341
  formatter,
319
342
  write(record, formatted) {
@@ -327,9 +350,14 @@ function createFileSink(options) {
327
350
  if (buffer.length > 0) {
328
351
  const content = buffer.join("");
329
352
  buffer.length = 0;
330
- const file = Bun.file(path);
331
- const existing = await file.exists() ? await file.text() : "";
332
- await Bun.write(path, existing + content);
353
+ if (append) {
354
+ const file = Bun.file(path);
355
+ const existing = await file.exists() ? await file.text() : "";
356
+ await Bun.write(path, existing + content);
357
+ return;
358
+ }
359
+ cachedContent = (cachedContent ?? "") + content;
360
+ await Bun.write(path, cachedContent);
333
361
  }
334
362
  }
335
363
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@outfitter/logging",
3
3
  "description": "Structured logging via logtape with redaction support for Outfitter",
4
- "version": "0.1.0",
4
+ "version": "0.2.0",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "dist"
@@ -27,7 +27,7 @@
27
27
  "clean": "rm -rf dist"
28
28
  },
29
29
  "dependencies": {
30
- "@outfitter/contracts": "0.1.0",
30
+ "@outfitter/contracts": "0.2.0",
31
31
  "@logtape/logtape": "^2.0.0"
32
32
  },
33
33
  "devDependencies": {