Back to skills
SkillHub ClubShip Full StackFull StackBackend

logging

How to do backend logging

Packaged view

This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.

Stars
10,265
Hot score
99
Updated
March 20, 2026
Overall rating
C4.0
Composite score
4.0
Best-practice grade
B77.6

Install command

npx @skill-hub/cli install elie222-inbox-zero-logging

Repository

elie222/inbox-zero

Skill path: .claude/skills/logging

How to do backend logging

Open repository

Best for

Primary workflow: Ship Full Stack.

Technical facets: Full Stack, Backend.

Target audience: everyone.

License: Unknown.

Original source

Catalog source: SkillHub Club.

Repository owner: elie222.

This is still a mirrored public skill entry. Review the repository before installing into production workflows.

What it helps with

  • Install logging into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
  • Review https://github.com/elie222/inbox-zero before adding logging to shared team environments
  • Use logging for development workflows

Works across

Claude CodeCodex CLIGemini CLIOpenCode

Favorites: 0.

Sub-skills: 0.

Aggregator: No.

Original source / Raw SKILL.md

---
name: logging
description: How to do backend logging
---
# Logging

We use a centralized, request-scoped logging pattern where loggers are created by middleware and passed through the request/function chain.

## API Route Logging (Primary Pattern)

Use middleware wrappers that automatically create loggers with request context:

```typescript
import { withError, withAuth, withEmailAccount, withEmailProvider } from "@/utils/middleware";

// Basic route with error handling and logging
export const POST = withError("my-route", async (request) => {
  const logger = request.logger;
  logger.info("Processing request");
  // ...
});

// Authenticated route - logger includes userId
export const GET = withAuth("my-route", async (request) => {
  request.logger.info("User action"); // Already has userId context
  // ...
});

// Email account route - logger includes emailAccountId, email
export const POST = withEmailAccount("my-route", async (request) => {
  request.logger.info("Email action"); // Has userId, emailAccountId, email
  // ...
});

// Email provider route - same as email account, plus provides emailProvider
export const GET = withEmailProvider("my-route", async (request) => {
  request.logger.info("Provider action");
  const emails = await request.emailProvider.getMessages();
  // ...
});
```

The middleware automatically adds:
- `requestId` - Unique ID for request tracing
- `url` - Request URL
- `userId` - For authenticated routes
- `emailAccountId`, `email` - For email account routes

### Enriching Logger Context

Add additional context within your route handler:

```typescript
export const POST = withEmailAccount("digest", async (request) => {
  let logger = request.logger;
  
  const body = await request.json();
  logger = logger.with({ messageId: body.messageId });
  
  logger.info("Processing message");
  // ...
});
```

## Helper Function Logging

Helper functions called from routes should receive the logger as a parameter instead of creating their own:

```typescript
import type { Logger } from "@/utils/logger";

export async function processEmail(
  emailId: string,
  logger: Logger,
) {
  logger = logger.with({ emailId });
  logger.info("Processing email");
  // ...
}
```

Then call from your route:

```typescript
export const POST = withEmailAccount("process", async (request) => {
  await processEmail(body.emailId, request.logger);
});
```

## Server Action Logging

Server actions using `actionClient` receive the logger through context, similar to route middleware:

```typescript
import { actionClient } from "@/utils/actions/safe-action";

export const createRuleAction = actionClient
  .metadata({ name: "createRule" })
  .inputSchema(createRuleBody)
  .action(
    async ({
      ctx: { emailAccountId, logger, provider },
      parsedInput: { name, actions },
    }) => {
      logger.info("Creating rule", { name });
      // ...
    },
  );
```

The `actionClient` context provides:
- `logger` - Scoped logger with request context
- `emailAccountId` - Current email account
- `provider` - Email provider type

## When to Use createScopedLogger

Use `createScopedLogger` only for code that doesn't run within a middleware chain (route or action):

```typescript
import { createScopedLogger } from "@/utils/logger";

// Standalone scripts
const logger = createScopedLogger("script/migrate");

// Tests
const logger = createScopedLogger("test");
```

Don't use `.with()` for a global/file-level logger. Only use within a specific function.
logging | SkillHub