Log Summaries

Log lines, as the operations tools show them to an LLM, and errors grouped by their signature.

The pod log tools of smarter.apps.mcpserver.logs.tools show log lines with format_line(), which puts the time, component and pod before each line, and cuts a long line with short(), so that one stack trace cannot fill the LLM’s context.

summarize_log_errors groups the warnings and errors of a period with error_groups(). A signature is a line’s message with what varies between occurrences removed: its timestamp, numbers, ids, hashes and quoted values. Lines with the same signature are the same problem, so error_groups() counts them, and keeps one example of each. A thousand timeouts of one provider then read as one group, with a count, rather than a thousand lines.

Everything here is plain Python over LogLine objects that the caller has already read: nothing is queried, cached or written.

Note

Experimental. The MCPServer was designed and coded by Claude Code (Anthropic’s Claude Opus 5.5), with Lawrence McDaniel as co-author. It is experimental, and will be documented.

class smarter.apps.mcpserver.logs.summary.ErrorGroup(component, level, signature, count=0, first_seen=None, last_seen=None, example='', pods=<factory>)[source]

Bases: object

The lines of one component that have the same level and signature: one problem, and how often it happened.

error_groups() creates the groups, and calls add() for each line. summarize_log_errors shows each group as a heading, its signature and its example.

__init__(component, level, signature, count=0, first_seen=None, last_seen=None, example='', pods=<factory>)
add(line)[source]

Count a line in the group.

The line’s time widens first_seen and last_seen, and the latest line is kept as the example. A line as late as the current example replaces it.

Parameters:

line (LogLine) – A line with the group’s component, level and signature.

Return type:

None

component: str

The component that wrote the lines, e.g. smarter-worker.

count: int = 0

How many lines the group has.

example: str = ''

The latest line’s text, cut with short().

first_seen: datetime | None = None

When the earliest line was written, in UTC, or None before the first add().

last_seen: datetime | None = None

When the latest line was written, in UTC, or None before the first add().

level: LogLevel | None

The lines’ level, or None if they name none.

pods: set[str]

The names of the pods that wrote the lines.

signature: str

The lines’ signature().

smarter.apps.mcpserver.logs.summary.MAX_LINE_CHARACTERS = 500

The most characters of one log line that a tool shows.

Longer lines are cut by short(), and end with an ellipsis.

smarter.apps.mcpserver.logs.summary.error_groups(lines)[source]

Group log lines by component, level and signature.

The same message from two components is two groups, since it is usually two problems.

Parameters:

lines (list[LogLine]) – The lines, e.g. the warnings and errors of the last hour.

Return type:

list[ErrorGroup]

Returns:

The groups, the most frequent first, then the most recent.

smarter.apps.mcpserver.logs.summary.format_line(line)[source]

Return a log line as a tool shows it: when, where, and its text.

The time is UTC, to the second, and the text is cut with short().

Parameters:

line (LogLine) – The line.

Return type:

str

Returns:

e.g. 2026-11-02 14:00:01 smarter-worker/smarter-worker-6f9c-x2: <text>.

smarter.apps.mcpserver.logs.summary.short(line, limit=500)[source]

Return a line, cut to a limit.

Parameters:
  • line (str) – The line’s text.

  • limit (int) – The most characters to return.

Return type:

str

Returns:

The line, if it is no longer than the limit, and otherwise its first limit - 1 characters followed by …, which is limit characters in all.

smarter.apps.mcpserver.logs.summary.signature(text)[source]

Return a log line’s signature: its message, without what varies between occurrences.

The leading timestamp is removed with TIMESTAMP_PREFIX, then each of VARIABLE_PARTS is replaced with its placeholder, e.g. 2026-11-02 14:00:01 - ERROR - timeout after 30s for 'gpt-4o' becomes ERROR - timeout after Ns for <str>.

Parameters:

text (str) – The line.

Return type:

str

Returns:

The signature, at most 200 characters.