Skip to content

feat(proxy): persist proxy logs to SQLite - #53

Merged
diegosouzapw merged 1 commit into
mainfrom
feature/proxy-log-sqlite-persistence
Feb 16, 2026
Merged

diegosouzapw merged 1 commit into
mainfrom
feature/proxy-log-sqlite-persistence

Conversation

@diegosouzapw

Copy link
Copy Markdown
Owner

Summary

Proxy logs were 100% in-memory — lost on every server restart. This PR adds SQLite persistence following the same pattern as callLogs.js.

Changes

  • src/lib/db/core.js — Added proxy_logs table (18 cols + 3 indexes)
  • src/lib/proxyLogger.js — Rewritten with hybrid dual storage:
    • In-memory ring buffer (real-time performance)
    • SQLite persistence (survives restarts)
    • On startup, hydrates from DB (last 500 entries)
    • Auto-trim keeps max 500 rows

Zero breaking changes

Same external API (getProxyLogs, clearProxyLogs, etc.). No changes needed in API route or frontend.

Verification

  • ✅ Build passes
  • ✅ All project tests pass

- Add proxy_logs table to db/core.js schema (18 columns + 3 indexes)
- Rewrite proxyLogger.js with hybrid dual storage:
  - In-memory ring buffer for real-time performance
  - SQLite persistence for surviving server restarts
  - On startup, hydrates from DB (last 500 entries)
  - Each event writes to both memory and SQLite
  - Auto-trim keeps max 500 rows in DB
- Same external API (getProxyLogs, clearProxyLogs, etc.)
- Zero changes needed in API route or frontend
Copilot AI review requested due to automatic review settings February 16, 2026 20:46
@github-actions

Copy link
Copy Markdown
Contributor

@codex review

@diegosouzapw
diegosouzapw merged commit c7abce2 into main Feb 16, 2026
3 checks passed
@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@diegosouzapw
diegosouzapw deleted the feature/proxy-log-sqlite-persistence branch February 16, 2026 20:46
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @diegosouzapw, 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 enhancement to how proxy logs are managed by transitioning from ephemeral in-memory storage to a robust hybrid system. By integrating SQLite persistence, the application can now retain proxy log history across restarts, greatly improving debugging and operational visibility without altering existing external interfaces. The change ensures that critical log data is durable while maintaining fast access for real-time monitoring.

Highlights

  • Proxy Log Persistence: Proxy logs, previously in-memory only, are now persisted to an SQLite database, ensuring they survive server restarts.
  • Hybrid Storage Implementation: The proxyLogger.js module has been rewritten to utilize a hybrid storage approach, combining an in-memory ring buffer for real-time performance with SQLite for durable persistence.
  • Database Hydration on Startup: Upon application startup, the proxy logger now hydrates its in-memory buffer with the last 500 entries from the SQLite database.
  • Automatic Log Trimming: Both the in-memory buffer and the SQLite database are configured to automatically trim older entries, maintaining a maximum of 500 proxy log records.
  • No Breaking API Changes: The external API for getProxyLogs and clearProxyLogs remains unchanged, ensuring no impact on existing API routes or frontend implementations.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • package-lock.json
    • Updated the project version from 0.7.0 to 0.8.0
    • Added a new dependency, 'wreq-js', version 2.0.1
  • src/lib/db/core.js
    • Created a new proxy_logs table in the SQLite schema with 18 columns
    • Added three indexes (idx_pl_timestamp, idx_pl_status, idx_pl_provider) to the proxy_logs table for efficient querying
  • src/lib/proxyLogger.js
    • Refactored the module to import database utilities (getDbInstance, isCloud, isBuildPhase)
    • Implemented a loadFromDb function to hydrate the in-memory proxyLogs array from SQLite on startup, fetching the last 500 entries
    • Modified the logProxyEvent function to persist new proxy log entries to the proxy_logs SQLite table, in addition to the in-memory buffer
    • Added logic within logProxyEvent to trim old entries from the SQLite database, maintaining a maximum of 500 records
    • Updated the clearProxyLogs function to also delete all entries from the proxy_logs SQLite table when clearing in-memory logs
Activity
  • The pull request author, diegosouzapw, provided a detailed summary of the changes and verification steps in the pull request description.
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. ↩

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

Copy link
Copy Markdown
Contributor

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 SQLite persistence for proxy logs, a significant improvement for log durability, moving from a purely in-memory solution. The implementation is solid and follows existing patterns in the codebase. My review includes two suggestions to enhance the changes: one to improve database schema integrity by enforcing non-nullable fields for status and level, and another to optimize the database trimming logic for better performance under high load.

Comment thread src/lib/db/core.js
Comment on lines +163 to +167
status TEXT,
proxy_type TEXT,
proxy_host TEXT,
proxy_port INTEGER,
level TEXT,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The status and level columns can be NULL, but the application logic in proxyLogger.js always provides default values ('success' and 'direct' respectively). This could mask issues where a log is saved without these values. To ensure data integrity, it's better to enforce this at the database level by making these columns NOT NULL.

Suggested change
status TEXT,
proxy_type TEXT,
proxy_host TEXT,
proxy_port INTEGER,
level TEXT,
status TEXT NOT NULL,
proxy_type TEXT,
proxy_host TEXT,
proxy_port INTEGER,
level TEXT NOT NULL,

Comment thread src/lib/proxyLogger.js
Comment on lines +132 to +140
// Trim old entries
const count = db.prepare("SELECT COUNT(*) as cnt FROM proxy_logs").get()?.cnt || 0;
if (count > MAX_ENTRIES) {
db.prepare(
`DELETE FROM proxy_logs WHERE id IN (
SELECT id FROM proxy_logs ORDER BY timestamp ASC LIMIT ?
)`
).run(count - MAX_ENTRIES);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The current implementation for trimming the database runs a COUNT(*) query and a DELETE query on every single log event. This can become a performance bottleneck, especially under high load, as COUNT(*) requires a full table scan. A more efficient approach would be to perform this cleanup operation periodically rather than on every write.

I suggest making the trimming logic probabilistic, for example, running it on average 1% of the time. This significantly reduces the overhead while still keeping the table size under control.

      // Trim old entries periodically to avoid overhead on every write.
      // This runs on average once every 100 calls.
      if (Math.random() < 0.01) {
        const count = db.prepare("SELECT COUNT(*) as cnt FROM proxy_logs").get()?.cnt || 0;
        if (count > MAX_ENTRIES) {
          db.prepare(
            `DELETE FROM proxy_logs WHERE id IN (
              SELECT id FROM proxy_logs ORDER BY timestamp ASC LIMIT ?
            )`
          ).run(count - MAX_ENTRIES);
        }
      }

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds durable persistence for proxy request logs by introducing a proxy_logs SQLite table and updating the proxy logger to write-through to SQLite while still maintaining an in-memory ring buffer for fast dashboard reads. This brings proxy logging in line with the existing SQLite-backed call log approach so logs survive server restarts.

Changes:

  • Added a proxy_logs table + indexes to the SQLite schema.
  • Reworked src/lib/proxyLogger.js to hydrate recent logs from SQLite at startup and persist new events while keeping an in-memory ring buffer.
  • Updated package-lock.json (version bump + includes wreq-js entry).

Reviewed changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated 1 comment.

File Description
src/lib/proxyLogger.js Hybrid in-memory + SQLite persistence for proxy logs, with startup hydration and DB trimming.
src/lib/db/core.js Extends SQLite schema with a new proxy_logs table and supporting indexes.
package-lock.json Lockfile updates including wreq-js metadata (engines/platform constraints).

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

Comment thread src/lib/proxyLogger.js
@@ -21,6 +71,7 @@ const proxyLogs = [];
* @param {string} [entry.error]
* @param {string} [entry.connectionId]
* @param {string} [entry.comboId]

Copilot AI Feb 16, 2026

Copy link

Choose a reason for hiding this comment

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

The JSDoc for logProxyEvent was updated (adds tlsFingerprint) but it still omits entry.account, even though account is read from entry and persisted to SQLite. Please document entry.account here to keep the public logger API accurate for callers.

Suggested change
* @param {string} [entry.comboId]
* @param {string} [entry.comboId]
* @param {string} [entry.account]

Copilot uses AI. Check for mistakes.
diegosouzapw added a commit that referenced this pull request Mar 10, 2026
TLS / Certificate Validation (#50)
- src/mitm/server.ts: rejectUnauthorized now defaults to true
  (opt-out via MITM_DISABLE_TLS_VERIFY=1 env var only)

Path Injection (#44, #41-#49)
- src/mitm/server.ts: safeLogPath() guards log filenames inside LOG_DIR
- src/lib/db/backup.ts: path.resolve() anchor + sep/slash guard on backupId
- src/shared/services/backupService.ts: safePath() helper anchors toolId
  and backupId within BACKUP_DIR (prevents path traversal)
- src/app/api/cli-tools/codex-profiles/route.ts: safeProfilePath() helper
  anchors profileId within PROFILES_DIR

Prototype Pollution (#18, #19, #20)
- src/lib/usage/usageHistory.ts: byModel/byAccount initialized with
  Object.create(null); assignments guarded with hasOwnProperty checks

Missing Workflow Permissions (#1-#8, #53)
- .github/workflows/ci.yml: added global permissions: contents: read

Dependabot CVE-2026-0540 (#16)
- dompurify updated to ^3.3.2 (fixes XSS vulnerability)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants