Skip to content

Comments

feat(session): add request/response headers logging with Tab UI#420

Merged
ding113 merged 2 commits intodevfrom
feat/issue-417-forward-logging
Dec 24, 2025
Merged

feat(session): add request/response headers logging with Tab UI#420
ding113 merged 2 commits intodevfrom
feat/issue-417-forward-logging

Conversation

@ding113
Copy link
Owner

@ding113 ding113 commented Dec 23, 2025

Summary

  • Add request/response headers storage and display in Session details page
  • Refactor UI from vertical layout to 4-tab layout (Request Headers / Request Body / Response Headers / Response Body)
  • Sensitive headers (authorization, x-api-key, etc.) are sanitized before storage
  • Headers stored in Redis with SESSION_TTL (5 min), auto-expire with session

Changes

File Description
src/lib/session-manager.ts Add headersToSanitizedObject, parseHeaderRecord, and 4 store/get methods
src/app/v1/_lib/proxy/forwarder.ts Store request headers after buildHeaders(), response headers after undici fetch
src/actions/active-sessions.ts Extend getSessionDetails to return requestHeaders/responseHeaders
session-messages-client.tsx Refactor to Tabs layout with HeadersDisplay component
messages/*/dashboard.json Add i18n keys for 5 locales

Test plan

  • Verify request headers are displayed correctly (with sensitive fields masked)
  • Verify response headers show upstream provider's original headers
  • Verify Tab switching works correctly
  • Verify empty state display when no headers data
  • Verify typecheck and lint pass

Closes #417

Generated with Claude Code

- Add headersToSanitizedObject and parseHeaderRecord helpers in session-manager.ts
- Store sanitized request/response headers to Redis with SESSION_TTL
- Extend getSessionDetails API to return requestHeaders/responseHeaders
- Refactor session details UI from vertical layout to 4-tab layout
- Add i18n keys for 5 locales (en, ja, ru, zh-CN, zh-TW)
- Add input validation for seq URL parameter to prevent NaN issues

Closes #417

Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @ding113, 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 significantly enhances the session monitoring capabilities by introducing the storage and display of both request and response headers. The session details page now features a more organized tabbed interface, allowing users to easily inspect header information alongside message and body content. A key security consideration has been addressed by implementing automatic sanitization of sensitive header fields before storage, and all header data is managed with a time-to-live in Redis to ensure efficient resource usage.

Highlights

  • Header Storage and Display: Request and response headers are now stored and displayed on the Session details page, providing more comprehensive session information.
  • UI Refactor to Tab Layout: The session details UI has been refactored from a vertical layout to a 4-tab layout, separating Request Headers, Request Body, Response Headers, and Response Body for improved readability and navigation.
  • Sensitive Header Sanitization: Sensitive headers, such as 'authorization' and 'x-api-key', are automatically sanitized before being stored, enhancing security and privacy.
  • Redis Storage with TTL: Stored headers are kept in Redis with a 5-minute TTL (Time To Live), ensuring they auto-expire with the session data.
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.

@github-actions
Copy link
Contributor

🧪 测试结果

测试类型 状态
代码质量
单元测试
集成测试
API 测试

总体结果: ✅ 所有测试通过

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 logging for request and response headers, and refactors the session details UI to a tab-based layout. The changes are well-structured and the new UI looks like a good improvement. I've identified a couple of areas with duplicated code and opportunities for simplification and performance improvement, which are detailed in the comments.

Comment on lines 15 to 21
function normalizeRequestSequence(requestSequence?: number): number | undefined {
if (typeof requestSequence !== "number") return undefined;
if (!Number.isFinite(requestSequence)) return undefined;
if (!Number.isInteger(requestSequence)) return undefined;
if (requestSequence <= 0) return undefined;
return requestSequence;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The validation logic in normalizeRequestSequence can be made more concise by combining the conditions into a single if statement. The !Number.isFinite(requestSequence) check is also redundant, as Number.isInteger() already ensures the number is finite.

Additionally, this function is duplicated in src/lib/session-manager.ts. Consider creating a single shared utility function to avoid code duplication and ensure consistency.

function normalizeRequestSequence(requestSequence?: number): number | undefined {
  if (typeof requestSequence !== "number" || !Number.isInteger(requestSequence) || requestSequence <= 0) {
    return undefined;
  }
  return requestSequence;
}

Comment on lines 15 to 21
function normalizeRequestSequence(requestSequence?: number): number | null {
if (typeof requestSequence !== "number") return null;
if (!Number.isFinite(requestSequence)) return null;
if (!Number.isInteger(requestSequence)) return null;
if (requestSequence <= 0) return null;
return requestSequence;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

This normalizeRequestSequence function is a near-duplicate of the one in src/actions/active-sessions.ts. To improve maintainability, this logic should be extracted to a shared utility file.

The validation can also be made more concise by combining the conditions. The !Number.isFinite() check is redundant because Number.isInteger() already covers it.

function normalizeRequestSequence(requestSequence?: number): number | null {
  if (typeof requestSequence !== "number" || !Number.isInteger(requestSequence) || requestSequence <= 0) {
    return null;
  }
  return requestSequence;
}

Comment on lines +23 to +46
function headersToSanitizedObject(headers: Headers): Record<string, string> {
const sanitizedText = sanitizeHeaders(headers);
if (!sanitizedText || sanitizedText === "(empty)") {
return {};
}

const obj: Record<string, string> = {};
const lines = sanitizedText.split(/\r?\n/).filter(Boolean);
for (const line of lines) {
const colonIndex = line.indexOf(":");
if (colonIndex === -1) continue;
const name = line.slice(0, colonIndex).trim();
const value = line.slice(colonIndex + 1).trim();
if (!name) continue;

if (obj[name]) {
obj[name] = `${obj[name]}\n${value}`;
} else {
obj[name] = value;
}
}

return obj;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

This function's implementation is a bit indirect. It converts a Headers object to a string using sanitizeHeaders, and then parses that string back into a Record<string, string>. This Headers -> string -> Record conversion can be inefficient.

A more direct approach would be to iterate over the Headers object and build the sanitized record directly. This would likely require exporting SENSITIVE_HEADERS, maskSensitiveValue, and maskAuthorizationValue from src/app/v1/_lib/proxy/errors.ts to be used here. This would improve performance and code clarity.

Here's an example of a more direct implementation:

function headersToSanitizedObject(headers: Headers): Record<string, string> {
  const obj: Record<string, string> = {};
  headers.forEach((value, key) => {
    const lowerKey = key.toLowerCase();
    // Assuming SENSITIVE_HEADERS and mask functions are available
    const sanitizedValue = SENSITIVE_HEADERS.has(lowerKey)
      ? lowerKey === "authorization"
        ? maskAuthorizationValue(value)
        : maskSensitiveValue(value)
      : value;

    // The forEach method handles multi-valued headers like Set-Cookie correctly
    if (obj[key]) {
      obj[key] += `\n${sanitizedValue}`;
    } else {
      obj[key] = sanitizedValue;
    }
  });
  return obj;
}

@github-actions github-actions bot added size/M Medium PR (< 500 lines) and removed size/M Medium PR (< 500 lines) labels Dec 23, 2025
Copy link
Contributor

@github-actions github-actions 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 Summary

This PR adds request/response headers logging and display functionality with a well-structured Tab UI. The implementation follows existing codebase patterns for Redis storage and correctly reuses the existing sanitizeHeaders function for sensitive data protection.

PR Size: M

  • Lines changed: 393 (325 additions + 68 deletions)
  • Files changed: 9

Issues Found

Category Critical High Medium Low
Logic/Bugs 0 0 0 0
Security 0 0 0 0
Error Handling 0 0 0 0
Types 0 0 0 0
Comments/Docs 0 0 0 0
Tests 0 0 1 0
Simplification 0 0 0 0

Medium Priority Issues (Should Consider)

  1. [TEST-MISSING-CRITICAL] src/lib/session-manager.ts - New methods lack unit tests

    The PR adds 4 new public methods (storeSessionRequestHeaders, storeSessionResponseHeaders, getSessionRequestHeaders, getSessionResponseHeaders) and 3 helper functions without corresponding test coverage. While the implementation correctly follows existing patterns in the codebase, unit tests would ensure:

    • normalizeRequestSequence handles edge cases correctly
    • parseHeaderRecord properly handles malformed JSON
    • Redis operations are mocked and verified

    Note: This is not blocking as the codebase's test coverage for session-manager.ts appears limited overall, but adding tests would improve confidence in the new functionality.

Review Coverage

  • Logic and correctness - Clean
  • Security (OWASP Top 10) - Clean (sensitive headers are properly sanitized via existing sanitizeHeaders function)
  • Error handling - Clean (errors are logged and fail gracefully)
  • Type safety - Clean
  • Documentation accuracy - Clean
  • Test coverage - Missing (see above)
  • Code clarity - Good

Positive Observations (Not counted as review items per instructions)

The implementation correctly:

  • Reuses existing sanitizeHeaders function from proxy/errors.ts
  • Follows the existing pattern of other Redis storage methods in SessionManager
  • Properly handles Redis unavailability with early returns
  • Uses fire-and-forget pattern (.catch()) for header storage to avoid blocking the request

Automated review by Claude AI

Copy link
Contributor

@github-actions github-actions 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 Summary

This PR adds request/response headers logging and display functionality with a well-structured Tab UI. The implementation follows existing codebase patterns for Redis storage and correctly reuses the existing sanitizeHeaders function for sensitive data protection.

PR Size: M

  • Lines changed: 393 (325 additions + 68 deletions)
  • Files changed: 9

Issues Found

Category Critical High Medium Low
Logic/Bugs 0 0 0 0
Security 0 0 0 0
Error Handling 0 0 0 0
Types 0 0 0 0
Comments/Docs 0 0 0 0
Tests 0 0 1 0
Simplification 0 0 0 0

Medium Priority Issues (Should Consider)

  1. [TEST-MISSING-CRITICAL] src/lib/session-manager.ts - New methods lack unit tests

    The PR adds 4 new public methods (storeSessionRequestHeaders, storeSessionResponseHeaders, getSessionRequestHeaders, getSessionResponseHeaders) and 3 helper functions without corresponding test coverage. While the implementation correctly follows existing patterns in the codebase, unit tests would ensure:

    • normalizeRequestSequence handles edge cases correctly
    • parseHeaderRecord properly handles malformed JSON
    • Redis operations are mocked and verified

    Note: This is not blocking as the codebase's test coverage for session-manager.ts appears limited overall, but adding tests would improve confidence in the new functionality.

Review Coverage

  • Logic and correctness - Clean
  • Security (OWASP Top 10) - Clean (sensitive headers are properly sanitized via existing sanitizeHeaders function)
  • Error handling - Clean (errors are logged and fail gracefully)
  • Type safety - Clean
  • Documentation accuracy - Clean
  • Test coverage - Missing (see above)
  • Code clarity - Good

Positive Observations (Not counted as review items per instructions)

The implementation correctly:

  • Reuses existing sanitizeHeaders function from proxy/errors.ts
  • Follows the existing pattern of other Redis storage methods in SessionManager
  • Properly handles Redis unavailability with early returns
  • Uses fire-and-forget pattern (.catch()) for header storage to avoid blocking the request

Automated review by Claude AI

}
}
return record;
} catch {
Copy link
Contributor

Choose a reason for hiding this comment

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

[CRITICAL] [ERROR-SILENT] JSON parse errors are swallowed when reading stored headers

Evidence: src/lib/session-manager.ts:60

  } catch {
    return null;
  }

Why this is a problem: If Redis contains invalid/legacy header JSON, the UI will silently show "No data" and you lose the signal needed to debug format drift or corruption.

Suggested fix:

function parseHeaderRecord(value: string): Record<string, string> {
  const parsed: unknown = JSON.parse(value);
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
    throw new Error("Invalid header record JSON");
  }

  const record: Record<string, string> = {};
  for (const [key, raw] of Object.entries(parsed as Record<string, unknown>)) {
    if (typeof raw === "string") record[key] = raw;
  }
  return record;
}

// In getSessionRequestHeaders / getSessionResponseHeaders
try {
  // ... const key = `session:${sessionId}:req:${sequence}:reqHeaders`
  return parseHeaderRecord(value);
} catch (error) {
  logger.warn("SessionManager: Invalid stored header record", { error, sessionId, key });
  return null;
}

Copy link
Contributor

@github-actions github-actions 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 Summary

This PR adds request/response header capture to Session details and refactors the UI to a 4-tab layout. The main blocker is silent JSON parse failure when reading stored headers, which can mask Redis data corruption/format drift and make missing header data hard to diagnose.

PR Size: M

  • Lines changed: 393
  • Files changed: 9

Issues Found

Category Critical High Medium Low
Logic/Bugs 0 0 0 0
Security 0 0 0 0
Error Handling 1 0 0 0
Types 0 0 0 0
Comments/Docs 0 0 0 0
Tests 0 0 0 0
Simplification 0 0 0 0

Critical Issues (Must Fix)

  • src/lib/session-manager.ts:60 [ERROR-SILENT] parseHeaderRecord swallows JSON parse errors and returns null without logging (Confidence: 95)

High Priority Issues (Should Fix)

  • None

Review Coverage

  • Logic and correctness
  • Security (OWASP Top 10)
  • Error handling
  • Type safety
  • Documentation accuracy
  • Test coverage
  • Code clarity

Automated review by Codex AI

@github-actions github-actions bot added the size/M Medium PR (< 500 lines) label Dec 23, 2025
Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

  • Reviewed PR #420 and applied label size/M (393 lines changed, 9 files).
  • Posted 1 inline blocking issue: src/lib/session-manager.ts:60parseHeaderRecord swallows JSON parse errors (catch { return null; }), which can hide Redis data corruption/format drift; suggested fix included in the inline comment.
  • Submitted the required PR review summary comment via gh pr review.

… and add JSON parse logging

- Extract normalizeRequestSequence to src/lib/utils/request-sequence.ts (DRY)
- Use Number.isSafeInteger() for stronger validation (per Codex review)
- Add logger.warn in parseHeaderRecord catch block for JSON parse failures
- Unify return type to number | null

Addresses PR #420 review feedback:
- Gemini: duplicate normalizeRequestSequence functions
- GitHub Actions: silent JSON parse error in parseHeaderRecord

Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@ding113 ding113 merged commit b2240f2 into dev Dec 24, 2025
6 of 8 checks passed
@github-project-automation github-project-automation bot moved this from Backlog to Done in Claude Code Hub Roadmap Dec 24, 2025
ding113 added a commit that referenced this pull request Dec 24, 2025
- Add tests for normalizeRequestSequence (edge cases, type errors)
- Add tests for parseHeaderRecord (JSON parsing, logger.warn verification)
- Add tests for headersToSanitizedObject (header conversion, colon handling)
- Export helper functions from session-manager.ts for testing

12 test cases covering all scenarios

Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@ding113 ding113 deleted the feat/issue-417-forward-logging branch December 30, 2025 17:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:i18n area:session area:UI enhancement New feature or request size/M Medium PR (< 500 lines)

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant