-
Notifications
You must be signed in to change notification settings - Fork 1.3k
added plugin logs in mcp logs #5740
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1629,13 +1629,7 @@ func (p *LoggerPlugin) Inject(_ context.Context, trace *schemas.Trace) error { | |
| return nil | ||
| } | ||
| // Serialize plugin logs once for all entries | ||
| var pluginLogsJSON string | ||
| if len(trace.PluginLogs) > 0 { | ||
| grouped := schemas.GroupPluginLogsByName(trace.PluginLogs) | ||
| if data, err := sonic.Marshal(grouped); err == nil { | ||
| pluginLogsJSON = string(data) | ||
| } | ||
| } | ||
| pluginLogsJSON := serializePluginLogs(trace.PluginLogs) | ||
| p.logger.Debug("Inject: enqueuing %d log entries", len(pending.entries)) | ||
| // Enqueue each log entry (supports multiple attempts per trace) | ||
| for _, entry := range pending.entries { | ||
|
|
@@ -1646,6 +1640,18 @@ func (p *LoggerPlugin) Inject(_ context.Context, trace *schemas.Trace) error { | |
| return nil | ||
| } | ||
|
|
||
| // serializePluginLogs groups plugin logs by plugin name for persistence and UI rendering. | ||
| func serializePluginLogs(logs []schemas.PluginLogEntry) string { | ||
| if len(logs) == 0 { | ||
| return "" | ||
| } | ||
| data, err := sonic.Marshal(schemas.GroupPluginLogsByName(logs)) | ||
| if err != nil { | ||
| return "" | ||
| } | ||
| return string(data) | ||
| } | ||
|
|
||
| // MCP Plugin Interface Implementation | ||
|
|
||
| // SetMCPToolLogCallback sets a callback function that will be called for each MCP tool log entry | ||
|
|
@@ -1910,6 +1916,7 @@ func (p *LoggerPlugin) PostMCPHook(ctx *schemas.BifrostContext, resp *schemas.Bi | |
| callback := p.mcpToolLogCallback | ||
| p.mu.Unlock() | ||
| attachMCPLogRedactionData(ctx, entry, p.contentLoggingEnabled(ctx)) | ||
| entry.PluginLogs = serializePluginLogs(ctx.GetPluginLogs()) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
rg -n -C 4 'GetPluginLogs|PluginLogEntry|contentLoggingEnabled|DisableContentLogging|\.Log\(' plugins core frameworkRepository: maximhq/bifrost Length of output: 50372 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- logging implementation ---'
rg -n -C 12 'entry\.PluginLogs|serializePluginLogs|func \(.*\) contentLoggingEnabled|func \(.*\) resolveContentPolicy|PluginLogEntry|GetPluginLogs' plugins/logging --glob '*.go'
printf '%s\n' '--- context log implementations ---'
rg -n -C 10 'func .*Log\(|PluginLogs|WithPluginScope|ReleasePluginScope' --glob '*.go' core framework plugins | head -n 1200
printf '%s\n' '--- plugin_logs response/API exposure ---'
rg -n -C 8 'plugin_logs|PluginLogs' --glob '*.go' --glob '*.sql' --glob '*.json' .Repository: maximhq/bifrost Length of output: 50372 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- exact update path ---'
sed -n '1820,1970p' plugins/logging/main.go
printf '%s\n' '--- policy helpers and nearby tests ---'
rg -n -C 20 'contentLoggingEnabled|resolveContentPolicy|ContentPolicy|DisableContentLogging' plugins/logging/main.go plugins/logging/*.go
printf '%s\n' '--- log entry schema and serializer ---'
rg -n -C 15 'type PluginLogEntry|func serializePluginLogs|serializePluginLogs\(' --glob '*.go' .Repository: maximhq/bifrost Length of output: 50372 🏁 Script executed: #!/bin/bash
set -euo pipefail
python3 - <<'PY'
import pathlib, re
roots = [pathlib.Path("plugins"), pathlib.Path("core"), pathlib.Path("framework")]
patterns = [
re.compile(r'\.Log\s*\('),
re.compile(r'PluginLogEntry'),
re.compile(r'GetPluginLogs'),
]
for root in roots:
for path in root.rglob("*.go"):
try:
text = path.read_text()
except Exception:
continue
hits = []
for i, line in enumerate(text.splitlines(), 1):
if any(p.search(line) for p in patterns):
hits.append((i, line.strip()))
if hits:
print(f"\n## {path}")
for i, line in hits:
print(f"{i}: {line}")
PYRepository: maximhq/bifrost Length of output: 24365 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- disabled-content tests and plugin-log tests ---'
rg -n -C 12 'PluginLogs|plugin logs|content.*log|log.*content|DisableContentLogging' plugins/logging/*_test.go
printf '%s\n' '--- all production plugin log writes ---'
rg -n -C 8 '\.Log\s*\(' plugins --glob '*.go' --glob '!**/*_test.go'Repository: maximhq/bifrost Length of output: 49224 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- repository stack metadata ---'
git status --short
git branch --all --no-color | head -n 100
find . -maxdepth 3 -type f \( -iname '*stack*' -o -name 'stack.yaml' -o -name 'stack.yml' \) -printRepository: maximhq/bifrost Length of output: 319 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- PluginLogEntry and context behavior ---'
sed -n '440,475p' core/schemas/bifrost.go
sed -n '730,815p' core/schemas/context.go
printf '%s\n' '--- MCP log schema, serialization, and hidden-content handling ---'
rg -n -C 12 'type MCPToolLog|PluginLogs.*string|ContentHidden|content_hidden|SerializeFields|DeserializeFields' framework/logstore core --glob '*.go'
printf '%s\n' '--- MCP log retrieval/API paths ---'
rg -n -C 10 'GetMCPToolLog|SearchMCPToolLogs|MCPToolLog' --glob '*.go' --glob '!**/*_test.go' . | head -n 1600Repository: maximhq/bifrost Length of output: 50372 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- PostMCPHook tests around content policy ---'
sed -n '1030,1155p' plugins/logging/operations_test.go
rg -n -C 15 'PostMCPHook|MCPToolLog|PluginLogs' plugins/logging/*_test.go | grep -E '^[^:]+:[0-9]+:|content|disabled|PluginLogs|PostMCPHook|MCPToolLog' | head -n 1200
printf '%s\n' '--- all production ctx.Log producers, excluding test files ---'
rg -n -C 5 '\.Log\s*\(' plugins --glob '*.go' --glob '!**/*_test.go'Repository: maximhq/bifrost Length of output: 15064 🏁 Script executed: #!/bin/bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
import re
path = Path("plugins/logging/main.go")
text = path.read_text()
start = text.index("func (p *LoggerPlugin) PostMCPHook")
end = text.index("\n}", start) + 2
body = text[start:end]
assignment = "entry.PluginLogs = serializePluginLogs(ctx.GetPluginLogs())"
print("post_mcp_hook_contains_unconditional_plugin_log_assignment:",
assignment in body)
print("assignment_count_in_post_mcp_hook:", body.count(assignment))
print("assignment_context:")
for line_no, line in enumerate(body.splitlines(), 1):
if "PluginLogs" in line or "contentLoggingEnabled" in line or "resolveContentPolicy" in line:
print(f"{line_no}: {line}")
policy = text[text.index("type contentPolicy"):text.index("// applyMCPGovernanceFieldsToEntry")]
print("content_logging_enabled_returns_store_content:",
"return p.resolveContentPolicy(ctx).storeContent" in text)
print("disabled_without_object_storage_returns_empty_policy:",
"return contentPolicy{}" in policy)
PYRepository: maximhq/bifrost Length of output: 699 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- exact logstore definitions ---'
rg -l 'type MCPToolLog|ContentHidden|PluginLogs' framework/logstore core | sort
for f in $(rg -l 'type MCPToolLog|ContentHidden|PluginLogs' framework/logstore core | sort | head -n 20); do
echo "## $f"
rg -n -C 20 'type MCPToolLog|PluginLogs|ContentHidden|content_hidden|SerializeFields|DeserializeFields' "$f"
doneRepository: maximhq/bifrost Length of output: 50372 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- API route and response serialization references ---'
rg -n -C 12 'mcp.*log|MCP.*log|plugin_logs|PluginLogs' . \
--glob '*.go' \
--glob '!**/*_test.go' \
--glob '!plugins/logging/main.go' \
--glob '!framework/logstore/*.go' | head -n 1800Repository: maximhq/bifrost Length of output: 50372 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- MCP payload preparation and serialization ---'
sed -n '1057,1135p' framework/logstore/tables.go
sed -n '385,435p' framework/logstore/payload.go
printf '%s\n' '--- MCP handler response paths ---'
sed -n '2555,2665p' transports/bifrost-http/handlers/logging.go
rg -n -A 45 -B 8 'func \(h \*LoggingHandler\) getMCPLogByID|func \(h \*LoggingHandler\) getMCPLogs' transports/bifrost-http/handlers/logging.goRepository: maximhq/bifrost Length of output: 18069 🏁 Script executed: #!/bin/bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
tables = Path("framework/logstore/tables.go").read_text()
payload = Path("framework/logstore/payload.go").read_text()
handler = Path("transports/bifrost-http/handlers/logging.go").read_text()
mcp_start = tables.index("type MCPToolLog struct")
mcp_end = tables.index("\n}", mcp_start) + 2
mcp = tables[mcp_start:mcp_end]
prep_start = payload.index("func PrepareMCPToolDBEntry")
prep_end = payload.index("\n}", prep_start) + 2
prep = payload[prep_start:prep_end]
print("mcp_plugin_logs_has_json_field:", '`json:"plugin_logs,omitempty"`' in mcp)
print("mcp_has_content_hidden_field:", "ContentHidden" in mcp)
print("prepare_mcp_clears_plugin_logs:", "PluginLogs =" in prep or "PluginLogs:" in prep)
print("handler_serializes_mcp_search_result:", "SendJSON(ctx, result)" in handler)
print("handler_serializes_mcp_detail_log:", "SendJSON(ctx, log)" in handler)
print("mcp_detail_route_present:", '"/api/mcp-logs/{id}"' in handler)
PYRepository: maximhq/bifrost Length of output: 379 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- exact MCP handler methods ---'
rg -n 'func \(h \*LoggingHandler\) (getMCPLogs|getMCPLogByID)' transports/bifrost-http/handlers/logging.go
for n in $(rg -n 'func \(h \*LoggingHandler\) (getMCPLogs|getMCPLogByID)' transports/bifrost-http/handlers/logging.go | cut -d: -f1); do
start=$((n-2)); end=$((n+100))
sed -n "${start},${end}p" transports/bifrost-http/handlers/logging.go
doneRepository: maximhq/bifrost Length of output: 15591 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- MCP content-hidden regression coverage ---'
sed -n '1,240p' framework/logstore/contenthidden_test.go
rg -n -C 12 'PluginLogs|plugin_logs|ContentHidden|content_hidden' framework/logstore/*_test.go plugins/logging/*_test.go transports/bifrost-http/handlers/*_test.goRepository: maximhq/bifrost Length of output: 50371 🏁 Script executed: #!/bin/bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
tables = Path("framework/logstore/tables.go").read_text()
payload = Path("framework/logstore/payload.go").read_text()
handler = Path("transports/bifrost-http/handlers/logging.go").read_text()
mcp_start = tables.index("type MCPToolLog struct")
mcp_end = tables.index("\n}", mcp_start) + 2
mcp = tables[mcp_start:mcp_end]
prep_start = payload.index("func PrepareMCPToolDBEntry")
prep_end = payload.index("\n}", prep_start) + 2
prep = payload[prep_start:prep_end]
print("mcp_plugin_logs_json_visible:", 'json:"plugin_logs,omitempty"' in mcp)
print("mcp_has_content_hidden_field:", "ContentHidden" in mcp)
print("prepare_mcp_clears_plugin_logs:", "PluginLogs" in prep)
print("handler_serializes_mcp_search_result:", "SendJSON(ctx, result)" in handler)
print("handler_serializes_mcp_detail_log:", "SendJSON(ctx, log)" in handler)
print("mcp_detail_route_present:", '"/api/mcp-logs/{id}"' in handler)
PYRepository: maximhq/bifrost Length of output: 376 Apply the visible-content policy to MCP plugin logs. When content is disabled or hidden, assign 🤖 Prompt for AI AgentsSources: Coding guidelines, Path instructions |
||
| p.enqueueMCPToolLogEntry(entry, callback) | ||
|
|
||
| return resp, bifrostErr, nil | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: maximhq/bifrost
Length of output: 240
🏁 Script executed:
Repository: maximhq/bifrost
Length of output: 50371
🏁 Script executed:
Repository: maximhq/bifrost
Length of output: 29352
Preserve the migration error chain.
Use
%winstead of%switherr.Error()so callers can inspect the underlying migration, database, or context error witherrors.Isanderrors.As.🤖 Prompt for AI Agents
Source: Coding guidelines