跳到主要内容

Logging Guidelines

Logging conventions for the Viben project


Overview

Viben uses structured logging with JSON format output, facilitating log analysis and monitoring.


Logging Libraries

TypeScript (packages/core)

Use Pino for logging:

import { createLogger, createDualLogger } from "@viben/core/telemetry";

// Create logger
const logger = process.env.NODE_ENV === "production"
? createLogger(config)
: createDualLogger(config); // Output to both file and console

Python (browse-mcp)

Use loguru for logging:

from loguru import logger

logger.info("Starting search")
logger.error(f"Search failed: {error}")

Log Levels

LevelTypeScriptPythonPurpose
tracelogger.trace()logger.trace()Very detailed debug information
debuglogger.debug()logger.debug()Debug information (development)
infologger.info()logger.info()General information (production default)
warnlogger.warn()logger.warning()Warning messages
errorlogger.error()logger.error()Error messages
fatallogger.fatal()logger.critical()Fatal errors

Level Selection Guide

ScenarioRecommended Level
Request start/endinfo
External API callsdebug
Parameter validation failurewarn
Exception caughterror
System crashfatal

Structured Logging

Module-Level Child Logger Pattern

Every module should create a child logger at the top level for consistent context:

import { logger as globalLogger } from "../telemetry";

// Create module-level child logger
const log = globalLogger.child({ module: "my-module-name" });

// Use throughout the module
log.info({ userId: "123" }, "Processing request");
log.error({ err: error, context: { userId: "123" } }, "Failed to process");

Basic Format

// Structured logging (recommended)
logger.info({
userId: user.id,
action: 'createAgent',
agentId: agent.id,
}, 'Agent created successfully');

// Simple message
logger.info('Server started');

Required Fields

FieldDescription
messageLog message
timestampTimestamp (auto-added)
levelLog level (auto-added)
FieldDescription
userIdUser ID
sessionIdSession ID
traceIdTrace ID
actionOperation name
durationOperation duration

What to Log

Request/Response

// Request start
logger.info({
method: 'POST',
path: '/api/agent',
body: requestBody,
}, 'API request received');

// Request completed
logger.info({
method: 'POST',
path: '/api/agent',
status: 200,
duration: '150ms',
}, 'API request completed');

Business Operations

// Important business operations
logger.info({
userId: user.id,
agentId: agent.id,
action: 'spawn',
}, 'Agent spawned');

// Status changes
logger.info({
taskId: task.id,
oldStatus: 'pending',
newStatus: 'running',
}, 'Task status changed');

Errors and Exceptions

// Error logging
logger.error({
error: error.message,
stack: error.stack,
userId: user.id,
action: 'createAgent',
}, 'Failed to create agent');

What Not to Log

Sensitive Data

Do Not LogReason
PasswordsSecurity risk
API keysSecurity risk
TokensSecurity risk
Personally Identifiable Information (PII)Privacy compliance

Automatic Redaction

The telemetry logger automatically redacts sensitive fields:

  • password, secret, token, apiKey, api_key
  • authorization, cookie
  • Fields matching patterns like *token, *secret, *key

Example

// Wrong - logging sensitive information
logger.info({
user: {
email: 'user@example.com',
password: 'secret123', // Never log
apiKey: 'sk-xxx', // Never log
},
}, 'User login');

// Correct - sanitized data
logger.info({
userId: user.id,
email: maskEmail(user.email), // Sanitized
action: 'login',
}, 'User login');

Safe Logging Examples

// Safe - log ID references, not sensitive data
log.info({ userId: user.id }, "User authenticated");

// Unsafe - don't log tokens
log.debug({ token: authToken }); // Don't do this!

// Safe alternative
log.debug({ tokenPrefix: authToken.slice(0, 8) + "..." }, "Token issued");

Log Storage

File Storage Structure

~/.viben/telemetry/logs/
└── YYYY-MM-DD.jsonl # Aggregated by date

Log Format (JSONL)

{"level":"info","time":1705312200000,"msg":"Server started","pid":12345}
{"level":"info","time":1705312201000,"msg":"Request received","method":"POST","path":"/api/agent"}

Log Configuration

Pino Configuration

const config = {
level: process.env.LOG_LEVEL || 'info',
formatters: {
level: (label) => ({ level: label }),
},
timestamp: pino.stdTimeFunctions.isoTime,
};

Environment Variables

VariableDescriptionDefault
LOG_LEVELLog levelinfo
LOG_FORMATLog formatjson

Debugging Tips

Enable Debug Logging

# Development environment
LOG_LEVEL=debug pnpm dev

# View specific module
DEBUG=viben:* pnpm dev

View Log Files

# View latest logs
tail -f ~/.viben/telemetry/logs/$(date +%Y-%m-%d).jsonl

# Format with jq
tail -f ~/.viben/telemetry/logs/*.jsonl | jq .

Best Practices

1. Consistent Module Naming

Use kebab-case for module names matching the file name:

// In telegram-poller.ts
const log = globalLogger.child({ module: "telegram-poller" });

// In preview.ts
const log = globalLogger.child({ module: "preview" });

2. Avoid Over-Logging

  • Use debug level for verbose output that's only useful during development
  • Use info level sparingly - only for significant events
  • Never log in tight loops without throttling

3. Include Actionable Context

Log enough context to debug issues without looking at source code:

// Good - includes context for debugging
log.error({
err: error,
taskId,
attempt: retryCount,
maxAttempts: 3
}, "Task execution failed");

// Poor - missing context
log.error("Task failed");

4. Use Appropriate Levels for Different Environments

  • Development: debug level
  • Production: info level (or warn for high-volume services)

The log level is configured via the LOG_LEVEL environment variable.


Migration Checklist

When migrating a file from console.log to the telemetry logger:

  1. Add import: import { logger as globalLogger } from "../telemetry";
  2. Create child logger: const log = globalLogger.child({ module: "module-name" });
  3. Replace each console call:
    • console.log("message") -> log.info("message")
    • console.log(`value: ${x}`) -> log.info({ x }, "value")
    • console.error("error:", err) -> log.error({ err }, "error")
  4. Verify with pnpm typecheck and pnpm build

Forbidden Patterns

Using console.log

// Wrong
console.log('User created:', user);

// Correct
logger.info({ userId: user.id }, 'User created');

Using print (Python)

# Wrong
print(f"Search result: {result}")

# Correct
logger.info(f"Search completed: {len(result)} results")