xiaohongshu
xiaohongshu
cross-platform-structured-logging
Unified JSON logging across Next.js, Python, and Firebase Functions using Pino and structlog. PROACTIVELY activate for: (1) Setting up structured logging, (2) Configuring Pino for Node.js, (3) Configuring structlog for Python, (4) Implementing PII redaction, (5) Log correlation with trace IDs. Tr...
Full skill instructions
Establish unified, machine-readable JSON logging across all platforms for centralized aggregation, powerful querying, and correlation with distributed traces.
Problem with traditional logging:
console.log('User ' + userId + ' logged in from ' + ip)
Structured logging solution:
logger.info('User logged in', {
user_id: userId,
ip_address: ip,
auth_method: 'oauth'
})
Output (JSON):
{
"level": "info",
"timestamp": "2024-01-15T10:30:00.000Z",
"message": "User logged in",
"user_id": "user_123",
"ip_address": "192.168.1.1",
"auth_method": "oauth",
"trace_id": "abc123...",
"service": "api"
}
Benefits:
user_id:user_123 AND level:errorUse consistent field names across all platforms:
| Field | Type | Description | Example |
|---|---|---|---|
| level | string/number | Log severity | "info", 30 |
| timestamp | ISO 8601 | When event occurred | "2024-01-15T10:30:00.000Z" |
| message | string | Human-readable message | "User logged in" |
| service.name | string | Service identifier | "api", "web", "worker" |
| service.version | string | Deployment version | "1.2.3" |
| environment | string | Runtime environment | "production", "staging" |
| trace_id | string | OpenTelemetry trace ID | "abc123..." |
| span_id | string | OpenTelemetry span ID | "def456..." |
| user_id | string | User identifier | "user_789" |
| request_id | string | Request identifier | "req_xyz" |
{
"http": {
"method": "POST",
"url": "/api/users",
"status_code": 201,
"user_agent": "Mozilla/5.0..."
},
"error": {
"type": "ValidationError",
"message": "Invalid email",
"stack": "Error: Invalid email\n at..."
}
}
Pino is the fastest JSON logger for Node.js.
// lib/logger.ts
import pino from 'pino'
const logger = pino({
level: process.env.LOG_LEVEL || 'info',
// Pretty print in development
transport: process.env.NODE_ENV === 'development'
? { target: 'pino-pretty', options: { colorize: true } }
: undefined,
// Base fields included in every log
base: {
service: {
name: process.env.SERVICE_NAME || 'api',
version: process.env.SERVICE_VERSION || '1.0.0'
},
environment: process.env.NODE_ENV || 'development'
},
// Redact sensitive fields
redact: {
paths: ['password', 'api_key', 'credit_card', '*.password', '*.token'],
censor: '[REDACTED]'
}
})
export default logger
import logger from '@/lib/logger'
// Simple message
logger.info('Server started')
// With context
logger.info({ user_id: '123', action: 'login' }, 'User logged in')
// Child logger (adds context to all subsequent logs)
const requestLogger = logger.child({ request_id: req.id })
requestLogger.info('Processing request')
requestLogger.error({ err }, 'Request failed')
// lib/logger-middleware.ts
import { NextRequest, NextResponse } from 'next/server'
import logger from '@/lib/logger'
export function withLogging(
handler: (req: NextRequest) => Promise<NextResponse>
) {
return async (req: NextRequest) => {
const requestLogger = logger.child({
request_id: crypto.randomUUID(),
http: {
method: req.method,
url: req.url
}
})
requestLogger.info('Request started')
try {
const response = await handler(req)
requestLogger.info({ status: response.status }, 'Request completed')
return response
} catch (error) {
requestLogger.error({ err: error }, 'Request failed')
throw error
}
}
}
// Usage in API route
export const GET = withLogging(async (req) => {
// Your handler logic
})
// lib/logger.ts (production)
import pino from 'pino'
const logger = pino({
level: 'info',
// Don't use pino-pretty in production (performance)
transport: process.env.NODE_ENV === 'production'
? {
target: 'pino/file',
options: { destination: 1 } // stdout
}
: { target: 'pino-pretty' },
// Async logging (don't block event loop)
destination: pino.destination({
sync: false // Async mode
})
})
export default logger
structlog integrates with Python's standard logging library.
# logging_config.py
import structlog
import logging
import sys
def configure_logging():
# Configure standard library logging
logging.basicConfig(
format="%(message)s",
stream=sys.stdout,
level=logging.INFO,
)
# Configure structlog
structlog.configure(
processors=[
# Add log level
structlog.stdlib.add_log_level,
# Add timestamp
structlog.processors.TimeStamper(fmt="iso"),
# Add calling location (file:line)
structlog.processors.CallsiteParameterAdder(
parameters=[
structlog.processors.CallsiteParameter.FILENAME,
structlog.processors.CallsiteParameter.LINENO,
]
),
# Format exceptions
structlog.processors.format_exc_info,
# Render as JSON
structlog.processors.JSONRenderer()
],
wrapper_class=structlog.stdlib.BoundLogger,
context_class=dict,
logger_factory=structlog.stdlib.LoggerFactory(),
cache_logger_on_first_use=True,
)
# Call at app startup
configure_logging()
import structlog
logger = structlog.get_logger()
# Simple message
logger.info("server_started", port=8000)
# With context
logger.info(
"user_logged_in",
user_id="user_123",
auth_method="oauth"
)
# Error logging
try:
risky_operation()
except Exception as e:
logger.error("operation_failed", exc_info=e)
# main.py
import structlog
from fastapi import FastAPI, Request
from uuid import uuid4
app = FastAPI()
@app.middleware("http")
async def logging_middleware(request: Request, call_next):
request_id = str(uuid4())
# Bind context for this request
logger = structlog.get_logger().bind(
request_id=request_id,
method=request.method,
path=request.url.path
)
logger.info("request_started")
try:
response = await call_next(request)
logger.info("request_completed", status_code=response.status_code)
return response
except Exception as e:
logger.error("request_failed", exc_info=e)
raise
# Integrate with OpenTelemetry
from opentelemetry import trace
logger = structlog.get_logger()
# Get current span
span = trace.get_current_span()
context = span.get_span_context()
# Log with trace context
logger.info(
"database_query",
trace_id=format(context.trace_id, '032x'),
span_id=format(context.span_id, '016x'),
query="SELECT * FROM users"
)
Firebase provides a built-in logger optimized for Cloud Logging.
// src/utils/logger.ts
import { logger } from 'firebase-functions'
export function log(message: string, data?: Record<string, any>) {
logger.info(message, {
...data,
service: 'firebase-functions',
environment: process.env.GCLOUD_PROJECT
})
}
export function logError(message: string, error: Error, data?: Record<string, any>) {
logger.error(message, {
...data,
error: {
type: error.name,
message: error.message,
stack: error.stack
}
})
}
import * as functions from 'firebase-functions'
import { log, logError } from './utils/logger'
export const myFunction = functions.https.onCall(async (data, context) => {
log('Function called', {
user_id: context.auth?.uid,
data
})
try {
const result = await processData(data)
log('Function completed', { result })
return result
} catch (error) {
logError('Function failed', error as Error, { data })
throw error
}
})
Cloud Run-based 2nd gen functions automatically inject execution_id:
import { onRequest } from 'firebase-functions/v2/https'
import { logger } from 'firebase-functions'
export const myHttpFunction = onRequest(async (req, res) => {
// execution_id automatically added by Cloud Run
logger.info('Processing request', {
path: req.path,
method: req.method
})
// Output includes: execution_id, trace, span_id
})
Never log sensitive data:
const logger = pino({
redact: {
paths: [
'password',
'api_key',
'credit_card',
'ssn',
'*.password',
'*.token',
'req.headers.authorization'
],
censor: '[REDACTED]'
}
})
logger.info({ password: 'secret123' }, 'User created')
// Output: { "password": "[REDACTED]", "message": "User created" }
def redact_sensitive_data(logger, method_name, event_dict):
"""Processor to redact sensitive fields"""
sensitive_fields = ['password', 'api_key', 'credit_card', 'ssn']
for field in sensitive_fields:
if field in event_dict:
event_dict[field] = '[REDACTED]'
return event_dict
structlog.configure(
processors=[
redact_sensitive_data, # Add as first processor
# ... other processors
]
)
// BAD
logger.info(`User ${userId} logged in from ${ip}`)
// GOOD
logger.info('User logged in', { user_id: userId, ip_address: ip })
// BAD
console.log('User logged in', userId)
// GOOD
logger.info('User logged in', { user_id: userId })
// BAD
logger.info('Login attempt', { password: req.body.password })
// GOOD
logger.info('Login attempt', { email: req.body.email })
// BAD (blocks event loop)
const logger = pino({ sync: true })
// GOOD (async)
const logger = pino({ sync: false })
Use appropriate levels:
| Level | When to Use | Example |
|---|---|---|
| debug | Verbose development info | Function entry/exit |
| info | Normal operations | Request completed |
| warn | Unexpected but handled | Deprecated API used |
| error | Errors requiring attention | Database connection failed |
| fatal | App cannot continue | Out of memory |
Test structured logging:
# Start service and make request
curl http://localhost:3000/api/test
# Check logs (should be JSON)
cat logs.json | jq '.'
# Verify fields present
cat logs.json | jq 'select(.trace_id != null)'
Query in Google Cloud Logging:
resource.type="cloud_run_revision"
jsonPayload.user_id="user_123"
jsonPayload.trace_id="abc123..."
xiaohongshu
technical spec
product ux expert
database patterns
Conduct multi-agent task orchestration and workflow coordination.
Initialize project with Conductor artifacts (product definition,
Expert in web animations, transitions, and motion design using Framer Motion and CSS
Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...
Display project status, active tracks, and next actions
Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience