feat(logging): add log line formatter
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
"""Logging configuration and utilities."""
|
"""Logging configuration and utilities."""
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
def extract_stats(tool_name: str, arguments: dict, result: dict) -> str:
|
def extract_stats(tool_name: str, arguments: dict, result: dict) -> str:
|
||||||
"""Extract meaningful stats from tool call based on tool type."""
|
"""Extract meaningful stats from tool call based on tool type."""
|
||||||
@@ -53,3 +55,29 @@ def truncate_token(token: str) -> str:
|
|||||||
if len(token) <= 8:
|
if len(token) <= 8:
|
||||||
return "***"
|
return "***"
|
||||||
return f"{token[:3]}...{token[-3:]}"
|
return f"{token[:3]}...{token[-3:]}"
|
||||||
|
|
||||||
|
|
||||||
|
def format_tool_log(
|
||||||
|
agent_name: str,
|
||||||
|
token: str,
|
||||||
|
tool: str,
|
||||||
|
document: str | None,
|
||||||
|
stats: str,
|
||||||
|
status: str,
|
||||||
|
duration_ms: int,
|
||||||
|
error_message: str | None = None,
|
||||||
|
) -> str:
|
||||||
|
"""Format a tool call log line.
|
||||||
|
|
||||||
|
Format: YYYY-MM-DD HH:MM:SS | agent (token) | tool | doc | stats | status | duration
|
||||||
|
"""
|
||||||
|
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
truncated = truncate_token(token)
|
||||||
|
doc = document if document else "-"
|
||||||
|
|
||||||
|
line = f"{timestamp} | {agent_name} ({truncated}) | {tool} | {doc} | {stats} | {status} | {duration_ms}ms"
|
||||||
|
|
||||||
|
if error_message:
|
||||||
|
line += f"\n {error_message}"
|
||||||
|
|
||||||
|
return line
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"""Unit tests for logging module."""
|
"""Unit tests for logging module."""
|
||||||
|
|
||||||
from grist_mcp.logging import truncate_token, extract_stats
|
from grist_mcp.logging import truncate_token, extract_stats, format_tool_log
|
||||||
|
|
||||||
|
|
||||||
class TestTruncateToken:
|
class TestTruncateToken:
|
||||||
@@ -71,3 +71,51 @@ class TestExtractStats:
|
|||||||
|
|
||||||
def test_unknown_tool(self):
|
def test_unknown_tool(self):
|
||||||
assert extract_stats("unknown_tool", {}, {}) == "-"
|
assert extract_stats("unknown_tool", {}, {}) == "-"
|
||||||
|
|
||||||
|
|
||||||
|
class TestFormatToolLog:
|
||||||
|
def test_success_format(self):
|
||||||
|
line = format_tool_log(
|
||||||
|
agent_name="dev-agent",
|
||||||
|
token="abcdefghijklmnop",
|
||||||
|
tool="get_records",
|
||||||
|
document="sales",
|
||||||
|
stats="42 records",
|
||||||
|
status="success",
|
||||||
|
duration_ms=125,
|
||||||
|
)
|
||||||
|
assert "dev-agent" in line
|
||||||
|
assert "abc...nop" in line
|
||||||
|
assert "get_records" in line
|
||||||
|
assert "sales" in line
|
||||||
|
assert "42 records" in line
|
||||||
|
assert "success" in line
|
||||||
|
assert "125ms" in line
|
||||||
|
# Check pipe-delimited format
|
||||||
|
assert line.count("|") == 6
|
||||||
|
|
||||||
|
def test_no_document(self):
|
||||||
|
line = format_tool_log(
|
||||||
|
agent_name="dev-agent",
|
||||||
|
token="abcdefghijklmnop",
|
||||||
|
tool="list_documents",
|
||||||
|
document=None,
|
||||||
|
stats="3 docs",
|
||||||
|
status="success",
|
||||||
|
duration_ms=45,
|
||||||
|
)
|
||||||
|
assert "| - |" in line
|
||||||
|
|
||||||
|
def test_error_format(self):
|
||||||
|
line = format_tool_log(
|
||||||
|
agent_name="dev-agent",
|
||||||
|
token="abcdefghijklmnop",
|
||||||
|
tool="add_records",
|
||||||
|
document="inventory",
|
||||||
|
stats="5 records",
|
||||||
|
status="error",
|
||||||
|
duration_ms=89,
|
||||||
|
error_message="Grist API error: Invalid column 'foo'",
|
||||||
|
)
|
||||||
|
assert "error" in line
|
||||||
|
assert "\n Grist API error: Invalid column 'foo'" in line
|
||||||
|
|||||||
Reference in New Issue
Block a user