Skip to content

feat(logging): Implement condensed access log format with request stack aggregation#196

Merged
polaz merged 22 commits intomainfrom
feat/#194-featlogging-implement-condensed-access-log-format
Jan 25, 2026
Merged

feat(logging): Implement condensed access log format with request stack aggregation#196
polaz merged 22 commits intomainfrom
feat/#194-featlogging-implement-condensed-access-log-format

Conversation

@polaz
Copy link
Copy Markdown
Member

@polaz polaz commented Jan 25, 2026

Summary

  • Implements single-line access log format (nginx/envoy inspired)
  • Aggregates all request events into one condensed entry on completion
  • Tracks connection statistics with close reasons
  • Uses AsyncLocalStorage for transparent context propagation
  • Configurable via LOG_FORMAT env var (condensed/verbose)
  • Shows session context and read-only mode in log lines

Access Log Format

nginx-style alignment: All fields always present with - for missing values.

[timestamp] ip session ctx ro method path status duration | tool action | gitlab_status gitlab_duration | details

Fields:

  • ctx - Selected context (project/namespace path) or -
  • ro - Read-only mode: RO if enabled, - if not

Examples:

# Successful tool call with context
[2026-01-25T12:34:56Z] 192.168.1.100 abc123.. mygroup/proj - POST /mcp 200 142ms | browse_projects list | GL:200 98ms | namespace=test items=15

# Read-only mode enabled
[2026-01-25T12:34:56Z] 192.168.1.100 abc123.. mygroup/proj RO POST /mcp 200 85ms | browse_files list | GL:200 45ms | path=src/

# No context, no read-only
[2026-01-25T12:34:56Z] 192.168.1.100 abc123.. - - POST /mcp 200 142ms | browse_projects list | GL:200 98ms | namespace=test items=15

# Health check (no tool, no GitLab call)
[2026-01-25T12:34:56Z] 192.168.1.100 - - - GET /health 200 5ms | - - | - - | -

# Rate limited
[2026-01-25T12:34:56Z] 192.168.1.100 - - - POST /mcp 429 2ms | - - | - - | rate_limit=true

Connection Close Format

[timestamp] CONN_CLOSE ip session duration reason | reqs=N tools=N errs=N

Example:

[2026-01-25T12:40:00Z] CONN_CLOSE 192.168.1.100 abc123.. 5m32s client_disconnect | reqs=42 tools=15 errs=0

Test plan

  • Unit tests for AccessLogFormatter (truncation, formatting, escaping)
  • Unit tests for RequestTracker (stack lifecycle, context)
  • Unit tests for ConnectionTracker (stats, close reasons)
  • All existing tests pass (4027 total)
  • Manual test with LOG_FORMAT=condensed
  • Manual test with LOG_FORMAT=verbose (backwards compat)

Closes #194

…ck aggregation

Implements single-line access log format inspired by nginx/envoy. Instead of
multiple log lines per request, all events are aggregated into a single
condensed entry when the request completes.

Features:
- Request stack aggregation: collect tool, action, GitLab response timing
- Single-line access log format with timestamp, client, session, method, path,
  status, duration, tool/action, GitLab status/duration, and details
- Connection tracking: log session stats (requests, tools, errors) on close
- AsyncLocalStorage for transparent context propagation through async calls
- LOG_FORMAT environment variable: "condensed" (default) or "verbose"

Access log format:
[timestamp] ip session method path status duration | tool action | gitlab_status gitlab_duration | details

Connection close format:
[timestamp] CONN_CLOSE ip session duration reason | reqs=N tools=N errs=N

Closes #194
Copilot AI review requested due to automatic review settings January 25, 2026 01:32
@polaz polaz requested review from Copilot and removed request for Copilot January 25, 2026 01:33
@codecov
Copy link
Copy Markdown

codecov bot commented Jan 25, 2026

Codecov Report

❌ Patch coverage is 81.53409% with 65 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/server.ts 57.97% 24 Missing and 5 partials ⚠️
src/handlers.ts 38.46% 14 Missing and 10 partials ⚠️
src/logging/request-tracker.ts 91.17% 0 Missing and 9 partials ⚠️
src/logging/access-log.ts 96.66% 1 Missing and 1 partial ⚠️
src/utils/fetch.ts 80.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown

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

Implements a new condensed, single-line access log format by aggregating request lifecycle events into a per-request “stack”, plus separate connection-close summary logs; behavior is toggled via LOG_FORMAT (condensed vs verbose).

Changes:

  • Added condensed access log formatting utilities and tracking types.
  • Introduced RequestTracker (AsyncLocalStorage-backed) and ConnectionTracker for aggregating request/connection stats.
  • Wired request/connection tracking into server request handling, tool dispatch, and GitLab fetch wrapper; added unit tests for the new logging components.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/server.ts Adds condensed logging initialization and middleware hooks for request/connection lifecycle tracking.
src/utils/fetch.ts Captures GitLab response status/duration into the current request context for access logs.
src/handlers.ts Records tool/action and errors into the request stack; increments connection tool/error counters.
src/config.ts Adds LOG_FORMAT parsing/configuration to select condensed vs verbose logging.
src/logging/types.ts Defines request stack / connection stats and log entry types for condensed logging.
src/logging/access-log.ts Implements access/connection-close line formatting and entry creation helpers.
src/logging/request-tracker.ts Implements request stack tracking + AsyncLocalStorage context helpers and singleton access.
src/logging/connection-tracker.ts Implements per-session connection stats tracking and close-summary logging.
src/logging/index.ts Aggregates exports for the new logging subsystem.
tests/unit/logging/access-log.test.ts Adds unit tests for formatting and entry creation utilities.
tests/unit/logging/request-tracker.test.ts Adds unit tests for request stack lifecycle and AsyncLocalStorage context helpers.
tests/unit/logging/connection-tracker.test.ts Adds unit tests for connection lifecycle tracking and close-summary formatting.

semantic-release-bot and others added 2 commits January 25, 2026 03:46
## [6.42.0](v6.41.4...v6.42.0) (2026-01-25)

### Features

* Token scope detection at startup with graceful degradation ([#190](#190)) ([28bab03](28bab03)), closes [#188](#188)

### Bug Fixes

* **workitems:** use two-step approach for timeEstimate on create ([#195](#195)) ([98abf4e](98abf4e)), closes [#193](#193)
… type

- All fields always present with "-" for missing values (nginx-style alignment)
- Escape quotes and backslashes in log values for safe parsing
- Import LogFormat from logging/types.ts to avoid type duplication
- Add comments explaining close handler behavior for new sessions
- Fix flaky test assertion using regex for duration matching
@github-actions
Copy link
Copy Markdown

github-actions bot commented Jan 25, 2026

Test Coverage Report

Overall Coverage: 93.59%

Metric Percentage
Statements 93.07%
Branches 84.8%
Functions 82.92%
Lines 93.59%

View detailed coverage report

Copy link
Copy Markdown

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 12 out of 12 changed files in this pull request and generated 4 comments.

polaz added 3 commits January 25, 2026 04:09
Add unit tests for LOG_FORMAT environment variable parsing:
- Default to 'condensed' when not set
- Parse 'verbose' value
- Case-insensitive parsing
- Invalid values default to 'condensed'
- Add ctx (context path) and ro (read-only) fields to access log format
- Capture session context and read-only state during tool execution
- Fix SSE close handling: distinguish normal disconnect from abort
- Fix session request counting: count initial request on session init
- Update session ID on stack after session initialization
- Escape newlines/tabs in log values to maintain single-line format
- Add needsQuoting helper to detect control characters

Access log format now:
[ts] ip session ctx ro method path status dur | tool action | GL:status dur | details
Copy link
Copy Markdown

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 13 changed files in this pull request and generated 4 comments.

polaz added 2 commits January 25, 2026 04:21
In condensed mode, suppress individual "Tool called", "Connection verified",
"Executing tool" INFO logs - these are aggregated into single access log line.
Also fix ConnectionTracker.closeConnection to return early when disabled.
Copy link
Copy Markdown

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 13 changed files in this pull request and generated 2 comments.

polaz added 2 commits January 25, 2026 04:31
- Gate access log tracking in handlers.ts behind LOG_FORMAT=condensed
- Add request tracking to SSE /messages handler:
  - Call connectionTracker.incrementRequests for each request
  - Update request stack with SSE session ID (query param vs header)
  - Wrap handlePostMessage in runWithRequestContextAsync
Copy link
Copy Markdown

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 13 changed files in this pull request and generated 3 comments.

polaz added 2 commits January 25, 2026 05:00
- Register access logging before rate limiter to capture 429 responses
- Update docstring format to include ctx and ro fields
- Correct comment about session ID availability in first request
Prevents TypeError when res.locals is undefined in test mocks.
Copy link
Copy Markdown

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 13 changed files in this pull request and generated 2 comments.

Prevents memory leak when setEnabled(false) is called while connections
are still open - connections are now always deleted from the map.
Copy link
Copy Markdown

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 13 changed files in this pull request and generated 2 comments.

- Update request stack with SSE session ID for access log
- Count initial GET /sse request in connection stats
Copy link
Copy Markdown

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 13 changed files in this pull request and generated no new comments.

@polaz polaz enabled auto-merge (squash) January 25, 2026 03:48
@polaz polaz merged commit 8871fad into main Jan 25, 2026
15 of 16 checks passed
@polaz polaz deleted the feat/#194-featlogging-implement-condensed-access-log-format branch January 25, 2026 03:50
sw-release-bot bot pushed a commit that referenced this pull request Jan 25, 2026
## [6.45.0](v6.44.0...v6.45.0) (2026-01-25)

### Features

* **logging:** Implement condensed access log format with request stack aggregation ([#196](#196)) ([8871fad](8871fad)), closes [#194](#194)

### Bug Fixes

* **docs:** replace hardcoded 'latest' MCPB link with versioned URL in README ([#206](#206)) ([a0266a4](a0266a4)), closes [#204](#204)
@sw-release-bot
Copy link
Copy Markdown

🎉 This PR is included in version 6.45.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(logging): Implement condensed access log format with request stack aggregation

3 participants