Skip to content

Conversation

@unnoq
Copy link
Member

@unnoq unnoq commented Nov 8, 2025

Fixes #908

Summary by CodeRabbit

  • New Features

    • Added a Pino-based structured per-request logging plugin with configurable lifecycle logging, abort handling, ID generation, and streaming error handling.
  • Documentation

    • Added a Pino integration guide and new navigation links in the docs.
  • Chores

    • Introduced a new experimental Pino package with package metadata, README, tsconfig and ignore rules.
  • Tests

    • Added tests covering logger context, plugin behavior, streaming/abort scenarios, and public exports.
  • Other

    • Broadened utility key typing to accept additional property key types.

@unnoq unnoq requested a review from Copilot November 8, 2025 09:49
@vercel
Copy link

vercel bot commented Nov 8, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
orpc Ready Ready Preview Comment Nov 9, 2025 7:23am

@dosubot dosubot bot added the size:XL This PR changes 500-999 lines, ignoring generated files. label Nov 8, 2025
@coderabbitai
Copy link

coderabbitai bot commented Nov 8, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds a new @orpc/experimental-pino package (sources, tests, tsconfig, README, .gitignore), implements a LoggingHandlerPlugin and context logger utilities, publishes Pino docs and VitePress navigation, and widens packages/shared/src/object.ts get() path type to readonly PropertyKey[].

Changes

Cohort / File(s) Summary
Docs / Site Navigation
apps/content/.vitepress/config.ts, apps/content/docs/integrations/pino.md
Adds a Pino integration docs page and sidebar entries; documents installation, plugin configuration, per-request logger usage, examples, and HTTP wiring.
Package metadata & project files
packages/pino/package.json, packages/pino/README.md, packages/pino/.gitignore, packages/pino/tsconfig.json
Adds new @orpc/experimental-pino package manifest, README, .gitignore, and TypeScript project configuration (exports, publishConfig, workspace deps).
Public API surface
packages/pino/src/index.ts, packages/pino/src/index.test.ts
Re-exports context and handler-plugin; test asserts LoggingHandlerPlugin is exported.
Context utilities & tests
packages/pino/src/context.ts, packages/pino/src/context.test.ts
Introduces CONTEXT_LOGGER_SYMBOL, LoggerContext type, and getLogger(context) accessor with tests verifying retrieval behavior.
Logging plugin & tests
packages/pino/src/handler-plugin.ts, packages/pino/src/handler-plugin.test.ts
Implements LoggingHandlerPlugin with per-request child logger creation, lifecycle and abort logging options, client interceptor adjustments, async-iterator stream error wrapping; comprehensive tests covering lifecycle, errors, aborts, streaming, and logger binding.
Shared utility type change
packages/shared/src/object.ts
Broadens get(object, path) signature: path changed from readonly string[] to readonly PropertyKey[]; implementation preserved.

Sequence Diagram(s)

sequenceDiagram
    actor Client
    participant Handler as StandardHandler
    participant Plugin as LoggingHandlerPlugin
    participant Logger as PinoLogger
    participant Ctx as Context

    Client->>Handler: send RPC request
    Handler->>Plugin: rootInterceptor(create per-request logger)
    Plugin->>Logger: create child logger (id, req meta)
    Plugin->>Ctx: attach logger via CONTEXT_LOGGER_SYMBOL
    Plugin-->>Handler: continue with enriched context

    Handler->>Plugin: interceptor — pre-exec
    Plugin->>Logger: info "request received" (if enabled)

    alt success
        Handler->>Handler: execute procedure
        Plugin->>Logger: info "request handled" (if enabled)
    else error
        Handler->>Plugin: interceptor catches error
        alt aborted signal
            Plugin->>Logger: info "request aborted" (if enabled)
        else business/internal error
            Plugin->>Logger: error(...)
        end
    end

    Note over Handler,Client: Streaming outputs are wrapped to log stream errors and preserve abort semantics
    Handler-->>Client: response / error
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Pay extra attention to:
    • packages/pino/src/handler-plugin.ts — interceptor ordering, abort vs error classification, async-iterator wrapping, child logger creation and binding.
    • packages/shared/src/object.ts — type change to PropertyKey[] may affect call sites and typings across the repo.
    • Comprehensive tests in packages/pino/src/handler-plugin.test.ts — many edge cases validating semantics.

Possibly related PRs

  • unnoq/orpc#855 — Similar docs/sidebar edits and integration page; may overlap VitePress navigation changes.
  • unnoq/orpc#210 — Modifies shared object utilities; directly related to the get() signature change.
  • unnoq/orpc#220 — Changes to handler/interceptor types used by the new LoggingHandlerPlugin; relevant to type compatibility.

Poem

🐰 I hopped through handlers, soft and keen,
I stitched a logger to every scene,
Pino hums as ids take flight,
Each request now tracked by night,
A little rabbit claps — delight. 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(pino): Logging Plugin' clearly and concisely summarizes the main change: adding a Pino-based logging plugin for oRPC.
Linked Issues check ✅ Passed The PR implements all key objectives from issue #908: logging request/response status and general info, capturing timing information, and logging errors with streaming support.
Out of Scope Changes check ✅ Passed All changes are directly related to the logging plugin feature: LoggingHandlerPlugin implementation, context-based logger management, documentation, package configuration, and a minor type expansion for the shared get utility supporting the plugin's needs.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch unnoq/issue908

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @unnoq, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a significant new feature: an experimental Pino logging plugin for oRPC. This plugin streamlines the process of adding structured logging, request tracking, and robust error monitoring to oRPC applications. It includes a new package, comprehensive documentation, and necessary updates to the build configuration and dependencies.

Highlights

  • Pino Logging Plugin: Introduced a new experimental plugin (@orpc/experimental-pino) for integrating Pino, a fast and lightweight JSON logger, with oRPC applications.
  • Structured Logging Capabilities: The new plugin enables structured logging, request tracking, and error monitoring for oRPC handlers, enhancing observability.
  • Comprehensive Documentation: Added a new documentation page (pino.md) detailing installation, setup, and usage of the Pino integration within oRPC, including examples for custom loggers and context access.
  • Dependency Updates: Updated various Vue-related dependencies to their latest versions (e.g., Vue 3.5.24) and incorporated new entries for the Pino package in pnpm-lock.yaml.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new experimental plugin for Pino integration, providing structured logging capabilities to oRPC applications. The implementation is well-structured, with comprehensive test coverage for various scenarios including request lifecycle, error handling, and streaming responses. The documentation is clear, though one of the code examples could be improved by adding missing imports to make it fully self-contained. Overall, this is a great addition to the oRPC ecosystem.

@codecov
Copy link

codecov bot commented Nov 8, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds a new Pino logging integration package and updates Vue dependencies from version 3.5.22 to 3.5.24.

  • Introduces @orpc/experimental-pino package for structured logging with Pino
  • Updates Vue from 3.5.22 to 3.5.24 across the monorepo
  • Enhances type safety of get function in shared package to accept PropertyKey[] instead of string[]

Reviewed Changes

Copilot reviewed 13 out of 14 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
pnpm-lock.yaml Updates dependency versions for Vue (3.5.22 → 3.5.24) and adds pino@10.1.0
packages/shared/src/object.ts Improves get function type signature to accept PropertyKey[] (includes symbols)
packages/pino/* New package providing Pino integration with LoggingHandlerPlugin, context utilities, and comprehensive tests
apps/content/docs/integrations/pino.md Documentation for the new Pino integration
apps/content/.vitepress/config.ts Adds navigation entries for Pino documentation
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (4)
packages/pino/src/index.test.ts (1)

1-3: Consider testing all public exports.

The test verifies that LoggingHandlerPlugin is exported, but other public exports like CONTEXT_LOGGER_SYMBOL, getLogger, and LoggerContext from the context module are not verified. Consider expanding this test to ensure all intended public API members are properly exported.

Apply this diff to test additional exports:

 it('exports LoggingHandlerPlugin', async () => {
-  expect(Object.keys(await import('./index'))).toContain('LoggingHandlerPlugin')
+  const exports = Object.keys(await import('./index'))
+  expect(exports).toContain('LoggingHandlerPlugin')
+  expect(exports).toContain('getLogger')
+  expect(exports).toContain('CONTEXT_LOGGER_SYMBOL')
 })
packages/pino/README.md (2)

48-48: Consider using more descriptive link text.

The link text "here" is generic. More descriptive text like "in the oRPC documentation" would improve accessibility and SEO.

Apply this diff:

-You can find the full documentation [here](https://orpc.unnoq.com).
+You can find the full documentation in [the oRPC documentation](https://orpc.unnoq.com).

74-76: Add alt text to the sponsor image.

The sponsor image is missing alt text, which is important for accessibility.

Apply this diff:

-    <img src='https://cdn.jsdelivr.net/gh/unnoq/unnoq/sponsors.svg'/>
+    <img src='https://cdn.jsdelivr.net/gh/unnoq/unnoq/sponsors.svg' alt='Sponsors'/>
packages/pino/src/handler-plugin.ts (1)

36-46: Reconsider the memory usage remark.

The remark states "If a signal is used for multiple requests, this may lead to un-efficient memory usage (listeners never removed)." However, line 111 uses { once: true }, which automatically removes the listener after it fires. The listener is also removed if the request completes without aborting (when the request ends, the signal's listeners are eligible for GC). This remark may be outdated or overly cautious.

Consider clarifying or removing this remark:

-  * @remarks If a signal is used for multiple requests, this may lead to un-efficient memory usage (listeners never removed).
+  * @remarks The listener is automatically removed after firing due to the { once: true } option.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4f6ce56 and 208d4f2.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (13)
  • apps/content/.vitepress/config.ts (2 hunks)
  • apps/content/docs/integrations/pino.md (1 hunks)
  • packages/pino/.gitignore (1 hunks)
  • packages/pino/README.md (1 hunks)
  • packages/pino/package.json (1 hunks)
  • packages/pino/src/context.test.ts (1 hunks)
  • packages/pino/src/context.ts (1 hunks)
  • packages/pino/src/handler-plugin.test.ts (1 hunks)
  • packages/pino/src/handler-plugin.ts (1 hunks)
  • packages/pino/src/index.test.ts (1 hunks)
  • packages/pino/src/index.ts (1 hunks)
  • packages/pino/tsconfig.json (1 hunks)
  • packages/shared/src/object.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
packages/pino/src/context.ts (1)
packages/shared/src/object.ts (1)
  • get (79-91)
packages/pino/src/context.test.ts (1)
packages/pino/src/context.ts (2)
  • getLogger (10-12)
  • CONTEXT_LOGGER_SYMBOL (4-4)
packages/pino/src/handler-plugin.ts (7)
packages/server/src/context.ts (1)
  • Context (1-1)
packages/server/src/adapters/standard/handler.ts (2)
  • StandardHandlerInterceptorOptions (23-25)
  • StandardHandlerOptions (27-48)
packages/server/src/adapters/standard/plugin.ts (1)
  • StandardHandlerPlugin (5-8)
packages/pino/src/context.ts (3)
  • LoggerContext (6-8)
  • CONTEXT_LOGGER_SYMBOL (4-4)
  • getLogger (10-12)
packages/shared/src/iterator.ts (2)
  • next (60-62)
  • isAsyncIteratorObject (6-12)
packages/shared/src/proxy.ts (1)
  • overlayProxy (62-83)
packages/client/src/event-iterator.ts (1)
  • mapEventIterator (4-52)
packages/shared/src/object.ts (1)
packages/openapi/src/openapi-custom.ts (1)
  • get (17-23)
packages/pino/src/handler-plugin.test.ts (7)
packages/standard-server/src/types.ts (1)
  • StandardLazyRequest (26-32)
packages/server/src/adapters/standard/rpc-codec.ts (1)
  • StandardRPCCodec (8-37)
packages/server/src/builder.ts (2)
  • handler (273-280)
  • os (336-352)
packages/server/src/adapters/standard/handler.ts (1)
  • StandardHandler (50-183)
packages/server/src/adapters/standard/rpc-matcher.ts (1)
  • StandardRPCMatcher (24-118)
packages/pino/src/handler-plugin.ts (1)
  • LoggingHandlerPlugin (49-172)
packages/pino/src/context.ts (2)
  • getLogger (10-12)
  • CONTEXT_LOGGER_SYMBOL (4-4)
🪛 Biome (2.1.2)
packages/pino/src/handler-plugin.test.ts

[error] 260-262: This generator function doesn't contain yield.

(lint/correctness/useYield)

🪛 LanguageTool
packages/pino/README.md

[style] ~54-~54: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ... your API or implement API contract. - [@orpc/client](https://www.npmjs.com/package/@...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~55-~55: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ... API on the client with type-safety. - [@orpc/openapi](https://www.npmjs.com/package/...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~56-~56: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...I specs and handle OpenAPI requests. - [@orpc/otel](https://www.npmjs.com/package/@or...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~57-~57: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ....io/) integration for observability. - [@orpc/nest](https://www.npmjs.com/package/@or...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~58-~58: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ... with NestJS. - [@orpc/react](https://www.npmjs.com/package/@o...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~59-~59: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...with React and React Server Actions. - [@orpc/tanstack-query](https://www.npmjs.com/p...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~60-~60: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...stack.com/query/latest) integration. - [@orpc/experimental-react-swr](https://www.npm...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~61-~61: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...ttps://swr.vercel.app/) integration. - [@orpc/vue-colada](https://www.npmjs.com/packa...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~62-~62: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...ada](https://pinia-colada.esm.dev/). - [@orpc/hey-api](https://www.npmjs.com/package/...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~63-~63: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...I](https://heyapi.dev/) integration. - [@orpc/zod](https://www.npmjs.com/package/@orp...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~64-~64: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...tps://zod.dev/) doesn't support yet. - [@orpc/valibot](https://www.npmjs.com/package/...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~65-~65: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...rom Valibot. - [@orpc/arktype](https://www.npmjs.com/package/...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

🪛 markdownlint-cli2 (0.18.1)
packages/pino/README.md

48-48: Link text should be descriptive

(MD059, descriptive-link-text)


75-75: Images should have alternate text (alt text)

(MD045, no-alt-text)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Agent
  • GitHub Check: test
  • GitHub Check: publish-commit
  • GitHub Check: lint
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (20)
packages/shared/src/object.ts (1)

79-79: Breaking API change enables symbol key support.

Expanding the path parameter from readonly string[] to readonly PropertyKey[] is a useful enhancement that enables the get function to work with symbol keys (as required by the new pino package's CONTEXT_LOGGER_SYMBOL). The implementation is compatible with this broader type.

This is a breaking change to the public API that should be noted in release documentation.

apps/content/.vitepress/config.ts (1)

156-156: LGTM! Dual navigation entry provides multiple discovery paths.

The Pino integration is appropriately listed in both the Plugins section (as "Logging") and the Integrations section (as "Pino"). This dual listing helps users discover the feature from either a capability perspective or a library perspective.

Also applies to: 194-194

packages/pino/src/index.ts (1)

1-2: LGTM! Clean barrel export pattern.

The index module properly re-exports all members from the context and handler-plugin modules, providing a clean public API surface.

packages/pino/src/context.test.ts (1)

4-10: LGTM! Comprehensive test coverage for getLogger.

The test properly covers both the negative cases (when no logger is present in the context) and the positive case (when a logger is attached via CONTEXT_LOGGER_SYMBOL). The test implementation is correct and validates the expected behavior.

packages/pino/tsconfig.json (1)

1-16: LGTM! Standard TypeScript library configuration.

The TypeScript configuration properly extends the shared library config, references the necessary dependencies (server and shared packages), and correctly includes/excludes files for a library build.

packages/pino/src/context.ts (2)

4-4: LGTM! Well-namespaced symbol identifier.

The CONTEXT_LOGGER_SYMBOL uses a descriptive, namespaced name (ORPC_PINO_CONTEXT_LOGGER_SYMBOL) that prevents collisions and clearly indicates its purpose.


10-12: LGTM! Clean implementation leveraging updated shared utility.

The getLogger function correctly uses the updated get() utility from @orpc/shared (which now accepts PropertyKey[] including symbols) to retrieve the logger from the context. The type assertion is safe since the symbol key is controlled by this module.

apps/content/docs/integrations/pino.md (3)

44-60: LGTM! Clear setup instructions with comprehensive options.

The setup example clearly demonstrates how to configure the LoggingHandlerPlugin with all available options including custom logger, ID generator, request lifecycle logging, and abort logging. The documentation appropriately notes that lifecycle and abort logging are disabled by default.


74-85: LGTM! Clear usage example with proper null safety.

The example correctly demonstrates accessing the logger via getLogger(context) and uses optional chaining (?.) for null safety, which is important since the logger might not be present in all contexts.


92-124: LGTM! Excellent advanced integration example.

The example demonstrates a practical pattern for integrating with pino-http, showing how to:

  • Extend the context interface with LoggerContext
  • Pass the per-request logger through the context using CONTEXT_LOGGER_SYMBOL
  • Properly type the context in the router

This is a valuable real-world use case that users will benefit from.

packages/pino/package.json (1)

1-46: LGTM! Well-structured package configuration.

The package.json is properly configured with appropriate metadata, exports, dependencies, and build scripts. The experimental prefix and version 0.0.0 appropriately signal the package's maturity level.

packages/pino/src/handler-plugin.test.ts (4)

9-46: LGTM! Well-designed test utilities.

The FakeLogger mock implementation effectively tracks method calls using shared spies while maintaining internal state. This provides a clean way to verify logger behavior without depending on actual pino instances.


65-90: LGTM! Comprehensive lifecycle logging verification.

The test properly validates both matched and unmatched request scenarios, ensuring the plugin logs appropriate messages for each case.


220-284: LGTM! Thorough streaming error handling tests.

The test suite properly validates that streaming errors are logged as errors while aborted stream errors are logged as info, maintaining the distinction between business logic errors and abort signals.

Note: The static analysis warning about the generator on line 260 not containing yield is a false positive—this test intentionally validates a generator that throws before yielding.


286-342: LGTM! Valuable edge case coverage.

These tests ensure proper handling of logger bindings, ID generation, and default logger initialization—critical behaviors that could easily be overlooked.

packages/pino/src/handler-plugin.ts (5)

10-47: LGTM! Well-documented options interface.

The interface provides clear documentation for each option with examples and sensible defaults. The type constraints ensure type safety across the plugin.


49-62: LGTM! Clean constructor with sensible defaults.

The constructor properly initializes all fields with appropriate defaults: a pino instance for the logger and crypto.randomUUID() for ID generation.


64-103: LGTM! Robust root interceptor setup.

The root interceptor properly:

  • Creates a child logger with per-request bindings
  • Generates unique request IDs
  • Preserves existing request bindings from pino-http
  • Logs internal errors to the base logger while propagating them

This provides a solid foundation for per-request logging context.


105-139: LGTM! Comprehensive request lifecycle interceptor.

The interceptor correctly handles:

  • Optional abort event logging
  • Request lifecycle logging when enabled
  • Distinguishing abort signals from business logic errors

The error handling logic appropriately logs aborted requests at info level while treating other errors as genuine errors.


141-171: LGTM! Well-designed client interceptor for streaming support.

The client interceptor properly:

  • Adds the procedure path to logger bindings
  • Handles both regular and streaming outputs
  • Applies the same abort-vs-error distinction for streaming errors

The use of overlayProxy with mapEventIterator ensures streaming errors are logged without breaking the iteration protocol.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Nov 8, 2025

More templates

@orpc/ai-sdk

npm i https://pkg.pr.new/@orpc/ai-sdk@1191

@orpc/arktype

npm i https://pkg.pr.new/@orpc/arktype@1191

@orpc/client

npm i https://pkg.pr.new/@orpc/client@1191

@orpc/contract

npm i https://pkg.pr.new/@orpc/contract@1191

@orpc/experimental-durable-iterator

npm i https://pkg.pr.new/@orpc/experimental-durable-iterator@1191

@orpc/hey-api

npm i https://pkg.pr.new/@orpc/hey-api@1191

@orpc/interop

npm i https://pkg.pr.new/@orpc/interop@1191

@orpc/json-schema

npm i https://pkg.pr.new/@orpc/json-schema@1191

@orpc/nest

npm i https://pkg.pr.new/@orpc/nest@1191

@orpc/openapi

npm i https://pkg.pr.new/@orpc/openapi@1191

@orpc/openapi-client

npm i https://pkg.pr.new/@orpc/openapi-client@1191

@orpc/otel

npm i https://pkg.pr.new/@orpc/otel@1191

@orpc/experimental-pino

npm i https://pkg.pr.new/@orpc/experimental-pino@1191

@orpc/experimental-publisher

npm i https://pkg.pr.new/@orpc/experimental-publisher@1191

@orpc/experimental-ratelimit

npm i https://pkg.pr.new/@orpc/experimental-ratelimit@1191

@orpc/react

npm i https://pkg.pr.new/@orpc/react@1191

@orpc/react-query

npm i https://pkg.pr.new/@orpc/react-query@1191

@orpc/experimental-react-swr

npm i https://pkg.pr.new/@orpc/experimental-react-swr@1191

@orpc/server

npm i https://pkg.pr.new/@orpc/server@1191

@orpc/shared

npm i https://pkg.pr.new/@orpc/shared@1191

@orpc/solid-query

npm i https://pkg.pr.new/@orpc/solid-query@1191

@orpc/standard-server

npm i https://pkg.pr.new/@orpc/standard-server@1191

@orpc/standard-server-aws-lambda

npm i https://pkg.pr.new/@orpc/standard-server-aws-lambda@1191

@orpc/standard-server-fastify

npm i https://pkg.pr.new/@orpc/standard-server-fastify@1191

@orpc/standard-server-fetch

npm i https://pkg.pr.new/@orpc/standard-server-fetch@1191

@orpc/standard-server-node

npm i https://pkg.pr.new/@orpc/standard-server-node@1191

@orpc/standard-server-peer

npm i https://pkg.pr.new/@orpc/standard-server-peer@1191

@orpc/svelte-query

npm i https://pkg.pr.new/@orpc/svelte-query@1191

@orpc/tanstack-query

npm i https://pkg.pr.new/@orpc/tanstack-query@1191

@orpc/trpc

npm i https://pkg.pr.new/@orpc/trpc@1191

@orpc/valibot

npm i https://pkg.pr.new/@orpc/valibot@1191

@orpc/vue-colada

npm i https://pkg.pr.new/@orpc/vue-colada@1191

@orpc/vue-query

npm i https://pkg.pr.new/@orpc/vue-query@1191

@orpc/zod

npm i https://pkg.pr.new/@orpc/zod@1191

commit: 6687c37

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
packages/pino/src/handler-plugin.ts (2)

42-42: Clarify the memory usage remark.

The comment states "listeners never removed," but the implementation at line 110 uses { once: true }, which auto-removes the listener after it fires. The actual concern is that if a signal is reused across multiple requests and never aborts between them, listeners accumulate until the signal finally aborts.

Apply this diff to clarify:

-   * @remarks If a signal is used for multiple requests, this may lead to un-efficient memory usage (listeners never removed).
+   * @remarks If a signal is reused across multiple requests without aborting, listeners accumulate (removed only when aborted or signal is garbage-collected).

94-101: Consider using per-request logger for consistency.

The catch block logs framework errors using this.logger (root logger) instead of the per-request logger created at line 71. Using the per-request logger would include the request ID and metadata in error logs, aiding troubleshooting.

If root logger usage is intentional (e.g., to separate framework errors), add a comment explaining the rationale:

       catch (error) {
         /**
-         * Any error here is internal (interceptor/framework), not business logic.
+         * Any error here is internal (interceptor/framework), not business logic.
+         * Logged to root logger to distinguish from per-request business logic errors.
          * Indicates unexpected handler failure.
          */
         this.logger.error(error)

Alternatively, use the per-request logger:

-        this.logger.error(error)
+        logger.error(error)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 144341c and 77ea969.

📒 Files selected for processing (2)
  • apps/content/docs/integrations/pino.md (1 hunks)
  • packages/pino/src/handler-plugin.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/content/docs/integrations/pino.md
🧰 Additional context used
🧬 Code graph analysis (1)
packages/pino/src/handler-plugin.ts (7)
packages/server/src/context.ts (1)
  • Context (1-1)
packages/server/src/adapters/standard/handler.ts (2)
  • StandardHandlerInterceptorOptions (23-25)
  • StandardHandlerOptions (27-48)
packages/server/src/adapters/standard/plugin.ts (1)
  • StandardHandlerPlugin (5-8)
packages/pino/src/context.ts (3)
  • LoggerContext (6-8)
  • CONTEXT_LOGGER_SYMBOL (4-4)
  • getLogger (10-12)
packages/shared/src/iterator.ts (2)
  • next (60-62)
  • isAsyncIteratorObject (6-12)
packages/shared/src/proxy.ts (1)
  • overlayProxy (62-83)
packages/client/src/event-iterator.ts (1)
  • mapEventIterator (4-52)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: lint
  • GitHub Check: test
  • GitHub Check: publish-commit
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (4)
packages/pino/src/handler-plugin.ts (4)

1-8: LGTM!

Clean and appropriate imports for the logging plugin implementation.


55-62: LGTM!

Constructor properly initializes with sensible defaults. The crypto.randomUUID() usage is safe given the Node.js version requirements.


104-138: LGTM!

The interceptor correctly distinguishes aborted signals from genuine errors (lines 130-132) and appropriately logs lifecycle events when enabled. The abort listener with { once: true } ensures cleanup after firing.


140-169: LGTM!

The client interceptor correctly adds path metadata to logger bindings and wraps streaming responses for error logging. The abort signal detection pattern (lines 156-158) is consistent with the regular interceptor, and returning the error unchanged (line 162) is correct for logging without altering the error flow.

@unnoq unnoq added the lgtm This PR has been approved by a maintainer label Nov 8, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
packages/pino/src/handler-plugin.ts (1)

94-105: Consider cleanup for abort listeners to prevent accumulation.

While the { once: true } option removes the listener after it fires, if the signal never aborts (request completes normally), the listener remains attached. With long-lived or reused signals, this can accumulate listeners over time, as noted in line 43.

Since logRequestAbort defaults to false and the comment warns users, this is acceptable. However, for robustness, consider explicitly removing the listener after the request completes:

 if (this.logRequestAbort) {
   const signal = interceptorOptions.request.signal
 
   if (signal?.aborted) {
     logger?.info(`request was aborted before handling (${String(signal.reason)})`)
   }
   else {
-    signal?.addEventListener('abort', () => {
-      logger?.info(`request is aborted (${String(signal.reason)})`)
-    }, { once: true })
+    const abortListener = () => {
+      logger?.info(`request is aborted (${String(signal.reason)})`)
+    }
+    signal?.addEventListener('abort', abortListener, { once: true })
+    
+    // Ensure cleanup if request completes without abort
+    try {
+      const result = await interceptorOptions.next(...)
+      return result
+    } finally {
+      signal?.removeEventListener('abort', abortListener)
+    }
   }
 }

Note: This would require restructuring the try-catch block.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8ff1ec5 and affe64d.

📒 Files selected for processing (1)
  • packages/pino/src/handler-plugin.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
packages/pino/src/handler-plugin.ts (7)
packages/server/src/context.ts (1)
  • Context (1-1)
packages/server/src/adapters/standard/handler.ts (2)
  • StandardHandlerInterceptorOptions (23-25)
  • StandardHandlerOptions (27-48)
packages/server/src/adapters/standard/plugin.ts (1)
  • StandardHandlerPlugin (5-8)
packages/pino/src/context.ts (3)
  • LoggerContext (6-8)
  • CONTEXT_LOGGER_SYMBOL (4-4)
  • getLogger (10-12)
packages/shared/src/iterator.ts (2)
  • next (60-62)
  • isAsyncIteratorObject (6-12)
packages/shared/src/proxy.ts (1)
  • overlayProxy (62-83)
packages/client/src/event-iterator.ts (1)
  • mapEventIterator (4-52)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: publish-commit
  • GitHub Check: lint
  • GitHub Check: test
🔇 Additional comments (4)
packages/pino/src/handler-plugin.ts (4)

10-48: LGTM!

The interface is well-documented with clear defaults and helpful examples. The memory leak remark on line 43 appropriately warns users about the tradeoff when enabling logRequestAbort with reused signals.


56-63: LGTM!

The constructor provides sensible defaults, including crypto.randomUUID() for ID generation and a fresh pino instance for logging.


146-164: LGTM!

The interceptor correctly distinguishes between aborted signals (logged as info) and genuine errors (logged as error), while preserving error propagation. The pattern request.signal?.aborted && request.signal.reason === error ensures we only treat the exact abort reason as a non-error case.


172-195: LGTM!

The async iterator wrapping correctly applies error logging to streaming responses while preserving abort signal semantics. The identity mapper at line 176 is necessary for the mapEventIterator API, and the error propagation at line 188 ensures downstream handlers receive the original error.

@unnoq unnoq requested a review from Copilot November 9, 2025 07:02
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 13 out of 14 changed files in this pull request and generated 5 comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
packages/pino/src/handler-plugin.test.ts (1)

261-265: Rename unused loop variable to avoid lint failure

TypeScript/tsconfig forbids unused locals; v isn’t read and will trip the build. Swap it for _ so the loop keeps consuming the stream without failing lint.

-      for await (const v of result1.response?.body as AsyncIterable<any>) {
+      for await (const _ of result1.response?.body as AsyncIterable<any>) {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between affe64d and 6687c37.

📒 Files selected for processing (2)
  • packages/pino/src/handler-plugin.test.ts (1 hunks)
  • packages/pino/src/handler-plugin.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/pino/src/handler-plugin.ts
🧰 Additional context used
🧬 Code graph analysis (1)
packages/pino/src/handler-plugin.test.ts (5)
packages/standard-server/src/types.ts (1)
  • StandardLazyRequest (26-32)
packages/server/src/adapters/standard/rpc-codec.ts (1)
  • StandardRPCCodec (8-37)
packages/server/src/adapters/standard/handler.ts (1)
  • StandardHandler (50-183)
packages/pino/src/handler-plugin.ts (1)
  • LoggingHandlerPlugin (50-197)
packages/pino/src/context.ts (2)
  • getLogger (10-12)
  • CONTEXT_LOGGER_SYMBOL (4-4)
🪛 Biome (2.1.2)
packages/pino/src/handler-plugin.test.ts

[error] 279-281: This generator function doesn't contain yield.

(lint/correctness/useYield)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: test
  • GitHub Check: publish-commit
  • GitHub Check: lint

@unnoq unnoq merged commit 4b03cd3 into main Nov 9, 2025
13 of 14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lgtm This PR has been approved by a maintainer size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Logger Plugin

1 participant