Documentation
¶
Overview ¶
Package logger provides the gateway logging implementations.
The package exposes three parallel global sink APIs:
- LogInfo / LogWarn / LogError / LogDebug for unified file/stdout logs
- LogInfoToMarkdown / LogWarnToMarkdown / LogErrorToMarkdown / LogDebugToMarkdown for markdown preview logs
- LogInfoToServer / LogWarnToServer / LogErrorToServer / LogDebugToServer for per-server logs
These APIs target different sinks and can be used together when a message should appear in multiple outputs. The unified file and markdown helper families share a common sink-dispatch path so new sink fan-out behavior stays centralized.
Per-type setup and error-handler functions ¶
Each logger type has its own setup* and handleError* functions (e.g. setupFileLogger / handleFileLoggerError, setupMarkdownLogger / handleMarkdownLoggerError). These are intentionally not collapsed into a single generic helper because each type has unique initialization behaviour:
- JSONLLogger has no fallback path (a failure returns an error directly).
- ToolsLogger writes a one-time header and closes the file immediately after opening, so its setup function owns that lifecycle step.
- FileLogger, MarkdownLogger, and RPCLogger each open a persistent file and wire up different formatters.
The per-type functions are bundled via the loggerFactory[T] generic defined in global_state.go, which handles the shared open-file / call-setup / call-onError flow.
Package logger provides structured logging for the MCP Gateway.
This file contains generic helper functions for managing global logger state with proper mutex handling. These helpers encapsulate common patterns for initializing and closing global loggers (FileLogger, JSONLLogger, MarkdownLogger) to reduce code duplication while maintaining thread safety.
Functions in this file follow a consistent pattern:
- init*: Initialize a global logger with proper locking and cleanup of any existing logger - close*: Close and clear a global logger with proper locking
The unexported helpers (withMutexLock, withGlobalLogger, initGlobalLogger, closeGlobalLogger) are used internally by the logger package and should not be called directly by external code. Use the public Init* and Close* functions instead. CloseAllLoggers is the public entry point for closing all global loggers at once.
Package logger provides structured logging for the MCP Gateway.
This file contains formatting and payload helper functions for RPC message logs.
Text Format: Compact, single-line format optimized for grep and command-line tools
Example: "github→tools/list 1234b {...}"
Markdown Format: Human-readable with syntax highlighting, suitable for documentation
Example: "**github**→`tools/list`\n\n```json\n{...}\n```"
Both formats use directional arrows (→ for outbound, ← for inbound) and support special handling for tools/call methods by extracting and displaying tool names.
Package logger provides structured logging for the MCP Gateway.
This file contains RPC message logging coordination, managing the flow of messages across multiple output formats (text, markdown, JSONL).
File Organization:
- rpc_logger.go (this file): Coordination of RPC logging across formats - rpc_format.go: Formatting and payload helper functions
The package supports logging RPC messages in three formats:
1. Text logs: Compact single-line format for grep-friendly searching 2. Markdown logs: Human-readable format with syntax highlighting 3. JSONL logs: Machine-readable format for structured analysis
Example:
logger.LogRPCRequest(logger.RPCDirectionOutbound, "github", "tools/list", payload, nil, nil) logger.LogRPCResponse(logger.RPCDirectionInbound, "github", responsePayload, nil, nil, nil)
Package logger provides structured logging for the MCP Gateway.
This file implements logging of MCP server tools to a JSON file (tools.json). It maintains a mapping of server IDs to their available tools with names and descriptions.
Index ¶
- Constants
- func CloseAllLoggers() error
- func Discard() *slog.Logger
- func InitFileLogger(logDir, fileName string) error
- func InitGatewayLoggers(logDir string)
- func InitJSONLLogger(logDir, fileName string) error
- func InitMarkdownLogger(logDir, fileName string) error
- func InitObservedURLDomainsLogger(logDir, fileName string) error
- func InitProxyLoggers(logDir string)
- func InitServerFileLogger(logDir string) error
- func InitToolsLogger(logDir, fileName string) error
- func LogDebug(category, format string, args ...interface{})
- func LogDebugToMarkdown(category, format string, args ...interface{})
- func LogDebugToServer(serverID, category, format string, args ...interface{})
- func LogDifcFilteredItem(entry *JSONLFilteredItem)
- func LogError(category, format string, args ...interface{})
- func LogErrorToMarkdown(category, format string, args ...interface{})
- func LogErrorToServer(serverID, category, format string, args ...interface{})
- func LogInfo(category, format string, args ...interface{})
- func LogInfoToMarkdown(category, format string, args ...interface{})
- func LogInfoToServer(serverID, category, format string, args ...interface{})
- func LogMarshaledForDebug(value interface{}, onMarshalSuccess func(string), onMarshalFailure func(error))
- func LogMarshaledForDebugf(value interface{}, onMarshalSuccessf func(string, ...interface{}), ...)
- func LogObservedURLDomains(serverID string, domains []string)
- func LogRPCMessage(info *RPCMessageInfo)
- func LogRPCMessageJSONL(direction RPCMessageDirection, messageType RPCMessageType, ...)
- func LogRPCMessageJSONLWithTags(direction RPCMessageDirection, messageType RPCMessageType, ...)
- func LogRPCRequest(direction RPCMessageDirection, serverID, method string, payload []byte, ...)
- func LogRPCResponse(direction RPCMessageDirection, serverID string, payload []byte, err error, ...)
- func LogToolsForServer(serverID string, tools []ToolInfo)
- func LogUnrecognizedEndpointPassthrough(method, path string)
- func LogWarn(category, format string, args ...interface{})
- func LogWarnToMarkdown(category, format string, args ...interface{})
- func LogWarnToServer(serverID, category, format string, args ...interface{})
- func NewSlogLogger(namespace string) *slog.Logger
- func NewSlogLoggerWithHandler(logger *Logger) *slog.Logger
- func SetURLDomainAuditEnabled(enabled bool)
- func ShutdownWarn(format string, args ...interface{})
- func StartupInfo(format string, args ...interface{})
- func StartupWarn(format string, args ...interface{})
- func URLDomainAuditEnabled() bool
- type FileLogger
- type FilteredItemLogEntry
- type JSONLFilteredItem
- type JSONLLogger
- type JSONLRPCMessage
- type JSONLUnrecognizedEndpointPassthrough
- type LogLevel
- type Logger
- type MarkdownLogger
- type ObservedURLDomainsLogger
- type RPCMessageDirection
- type RPCMessageInfo
- type RPCMessageType
- type ServerFileLogger
- type SlogHandler
- type ToolInfo
- type ToolsData
- type ToolsLogger
Constants ¶
const ( // EnvDebug is the environment variable for debug logging patterns. // Supports patterns like "*", "namespace:*", "ns1,ns2", "ns:*,-ns:skip" EnvDebug = "DEBUG" // EnvDebugColors controls colored output in debug logs. // Set to "0" to disable colors. EnvDebugColors = "DEBUG_COLORS" )
Environment variable names for logging configuration
const ( // MaxPayloadPreviewLengthText is the maximum number of characters to include in text log preview (10KB) MaxPayloadPreviewLengthText = 10 * 1024 // 10KB // MaxPayloadPreviewLengthMarkdown is the maximum number of characters to include in markdown log preview MaxPayloadPreviewLengthMarkdown = 512 )
Variables ¶
This section is empty.
Functions ¶
func CloseAllLoggers ¶ added in v0.2.20
func CloseAllLoggers() error
CloseAllLoggers closes all global loggers in a single call. Returns the first error encountered, but attempts to close every logger.
func InitFileLogger ¶
InitFileLogger initializes the global file logger If the log directory doesn't exist and can't be created, falls back to stderr
func InitGatewayLoggers ¶ added in v0.2.18
func InitGatewayLoggers(logDir string)
InitGatewayLoggers initializes the standard set of gateway loggers for the given log directory. Failures are printed as warnings but do not abort startup.
func InitJSONLLogger ¶
InitJSONLLogger initializes the global JSONL logger
func InitMarkdownLogger ¶
InitMarkdownLogger initializes the global markdown logger
func InitObservedURLDomainsLogger ¶ added in v0.3.29
InitObservedURLDomainsLogger initializes observed-url-domains.json logger.
func InitProxyLoggers ¶ added in v0.2.18
func InitProxyLoggers(logDir string)
InitProxyLoggers initializes the subset of loggers used by the proxy command. Failures are printed as warnings but do not abort startup.
func InitServerFileLogger ¶ added in v0.0.102
InitServerFileLogger initializes the global server file logger
func InitToolsLogger ¶ added in v0.1.1
InitToolsLogger initializes the global tools logger If the log directory doesn't exist and can't be created, falls back to no-op
func LogDebug ¶
func LogDebug(category, format string, args ...interface{})
LogDebug logs a debug message to the unified file logger sink. The underlying filename depends on logger initialization. For destination-specific logging use LogDebugToMarkdown or LogDebugToServer.
func LogDebugToMarkdown ¶ added in v0.3.7
func LogDebugToMarkdown(category, format string, args ...interface{})
LogDebugToMarkdown logs to both regular and markdown loggers.
func LogDebugToServer ¶ added in v0.3.7
func LogDebugToServer(serverID, category, format string, args ...interface{})
LogDebugToServer logs a debug message to the server-specific log file.
func LogDifcFilteredItem ¶ added in v0.1.17
func LogDifcFilteredItem(entry *JSONLFilteredItem)
LogDifcFilteredItem writes a DIFC filter event to the JSONL log.
func LogError ¶
func LogError(category, format string, args ...interface{})
LogError logs an error message to the unified file logger sink. The underlying filename depends on logger initialization. For destination-specific logging use LogErrorToMarkdown or LogErrorToServer.
func LogErrorToMarkdown ¶ added in v0.3.7
func LogErrorToMarkdown(category, format string, args ...interface{})
LogErrorToMarkdown logs to both regular and markdown loggers.
func LogErrorToServer ¶ added in v0.3.7
func LogErrorToServer(serverID, category, format string, args ...interface{})
LogErrorToServer logs an error message to the server-specific log file.
func LogInfo ¶
func LogInfo(category, format string, args ...interface{})
LogInfo logs an informational message to the unified file logger sink. The underlying filename depends on logger initialization. For destination-specific logging use LogInfoToMarkdown or LogInfoToServer.
func LogInfoToMarkdown ¶ added in v0.3.7
func LogInfoToMarkdown(category, format string, args ...interface{})
LogInfoToMarkdown logs to both regular and markdown loggers.
func LogInfoToServer ¶ added in v0.3.7
func LogInfoToServer(serverID, category, format string, args ...interface{})
LogInfoToServer logs an informational message to the server-specific log file.
func LogMarshaledForDebug ¶ added in v0.2.25
func LogMarshaledForDebug(value interface{}, onMarshalSuccess func(string), onMarshalFailure func(error))
LogMarshaledForDebug marshals value for debug logging and dispatches to the provided callbacks for success or marshal failure paths.
func LogMarshaledForDebugf ¶ added in v0.3.27
func LogMarshaledForDebugf(
value interface{},
onMarshalSuccessf func(string, ...interface{}),
successFormat string,
onMarshalFailuref func(string, ...interface{}),
failureFormat string,
args ...interface{},
)
LogMarshaledForDebugf marshals value for debug logging and dispatches to formatted logging functions for success or marshal failure paths.
func LogObservedURLDomains ¶ added in v0.3.29
LogObservedURLDomains appends newly observed domains for a server.
func LogRPCMessage ¶
func LogRPCMessage(info *RPCMessageInfo)
LogRPCMessage logs a generic RPC message with custom info. It uses the withGlobalLogger helper from global_helpers.go to handle mutex locking and nil-checking.
func LogRPCMessageJSONL ¶
func LogRPCMessageJSONL(direction RPCMessageDirection, messageType RPCMessageType, serverID, method string, payloadBytes []byte, err error)
LogRPCMessageJSONL logs an RPC message to the global JSONL logger
func LogRPCMessageJSONLWithTags ¶ added in v0.1.10
func LogRPCMessageJSONLWithTags(direction RPCMessageDirection, messageType RPCMessageType, serverID, method string, payloadBytes []byte, err error, agentSecrecy, agentIntegrity []string)
LogRPCMessageJSONLWithTags logs an RPC message to the global JSONL logger with optional agent tag snapshots. It uses the withGlobalLogger helper from global_helpers.go to handle mutex locking and nil-checking.
func LogRPCRequest ¶
func LogRPCRequest(direction RPCMessageDirection, serverID, method string, payload []byte, agentSecrecy, agentIntegrity []string)
LogRPCRequest logs an RPC request message to text, markdown, and JSONL logs. agentSecrecy and agentIntegrity are optional and only affect JSONL output.
func LogRPCResponse ¶
func LogRPCResponse(direction RPCMessageDirection, serverID string, payload []byte, err error, agentSecrecy, agentIntegrity []string)
LogRPCResponse logs an RPC response message to text, markdown, and JSONL logs. agentSecrecy and agentIntegrity are optional and only affect JSONL output.
func LogToolsForServer ¶ added in v0.1.1
LogToolsForServer logs the tools for a specific server. It uses the withGlobalLogger helper from global_helpers.go to handle mutex locking and nil-checking.
func LogUnrecognizedEndpointPassthrough ¶ added in v0.3.25
func LogUnrecognizedEndpointPassthrough(method, path string)
LogUnrecognizedEndpointPassthrough writes the proxy's unrecognized-endpoint passthrough event to the standard text log, markdown artifact log, and JSONL log.
func LogWarn ¶
func LogWarn(category, format string, args ...interface{})
LogWarn logs a warning message to the unified file logger sink. The underlying filename depends on logger initialization. For destination-specific logging use LogWarnToMarkdown or LogWarnToServer.
func LogWarnToMarkdown ¶ added in v0.3.7
func LogWarnToMarkdown(category, format string, args ...interface{})
LogWarnToMarkdown logs to both regular and markdown loggers.
func LogWarnToServer ¶ added in v0.3.7
func LogWarnToServer(serverID, category, format string, args ...interface{})
LogWarnToServer logs a warning message to the server-specific log file.
func NewSlogLogger ¶
NewSlogLogger creates a new slog.Logger that uses gh-aw's logger package This allows integration with libraries that expect slog.Logger
func NewSlogLoggerWithHandler ¶
NewSlogLoggerWithHandler creates a new slog.Logger using an existing Logger instance
func SetURLDomainAuditEnabled ¶ added in v0.3.29
func SetURLDomainAuditEnabled(enabled bool)
SetURLDomainAuditEnabled toggles URL domain observation for middleware and guards.
func ShutdownWarn ¶ added in v0.4.2
func ShutdownWarn(format string, args ...interface{})
ShutdownWarn logs a shutdown warning message to stderr (via log.Printf with "Warning: " prefix) and to the shutdown warning log sink (via LogWarn with "shutdown" category).
func StartupInfo ¶ added in v0.2.18
func StartupInfo(format string, args ...interface{})
StartupInfo logs a startup informational message to stderr (via log.Printf) and to the startup markdown/file log sink (via LogInfoToMarkdown with "startup" category). This eliminates the need to call log.Printf and LogInfoToMarkdown separately for the same message.
func StartupWarn ¶ added in v0.2.18
func StartupWarn(format string, args ...interface{})
StartupWarn logs a startup warning message to stderr (via log.Printf with "Warning: " prefix) and to the startup warning log sink (via LogWarn with "startup" category). This eliminates the need to call log.Printf and LogWarn separately for the same message.
func URLDomainAuditEnabled ¶ added in v0.3.29
func URLDomainAuditEnabled() bool
URLDomainAuditEnabled reports whether URL domain observation is enabled.
Types ¶
type FileLogger ¶
type FileLogger struct {
// contains filtered or unexported fields
}
FileLogger manages logging to a file with fallback to stderr
func (*FileLogger) GetWriter ¶
func (fl *FileLogger) GetWriter() io.Writer
GetWriter returns the underlying io.Writer for the file logger
func (*FileLogger) Log ¶
func (fl *FileLogger) Log(level LogLevel, category, format string, args ...interface{})
Log writes a log message with the specified level and category
type FilteredItemLogEntry ¶ added in v0.1.19
type FilteredItemLogEntry struct {
ServerID string `json:"server_id"`
ToolName string `json:"tool_name"`
Description string `json:"description"`
Reason string `json:"reason"`
SecrecyTags []string `json:"secrecy_tags"`
IntegrityTags []string `json:"integrity_tags"`
AuthorAssociation string `json:"author_association,omitempty"`
AuthorLogin string `json:"author_login,omitempty"`
HTMLURL string `json:"html_url,omitempty"`
Number string `json:"number,omitempty"`
SHA string `json:"sha,omitempty"`
}
FilteredItemLogEntry holds the data fields for a DIFC-filtered item. It is used for both text log output ([DIFC-FILTERED] JSON lines) and as the embedded payload in JSONLFilteredItem for JSONL log output.
type JSONLFilteredItem ¶ added in v0.1.17
type JSONLFilteredItem struct {
Timestamp string `json:"timestamp"`
Event string `json:"event"` // Always "difc_filtered"
Schema string `json:"_schema"` // "difc-filtered/v2"
FilteredItemLogEntry
}
JSONLFilteredItem represents a DIFC-filtered item logged to the JSONL stream. These entries appear alongside RPC messages so filter events are visible in context with the request/response that triggered them. It embeds FilteredItemLogEntry so that adding a data field requires only a single edit rather than parallel edits in two structs.
type JSONLLogger ¶
type JSONLLogger struct {
// contains filtered or unexported fields
}
JSONLLogger manages logging RPC messages to a JSONL file (one JSON object per line)
func (*JSONLLogger) LogMessage ¶
func (jl *JSONLLogger) LogMessage(entry *JSONLRPCMessage) error
LogMessage logs an RPC message to the JSONL file
type JSONLRPCMessage ¶
type JSONLRPCMessage struct {
Timestamp string `json:"timestamp"`
Event string `json:"event"` // "rpc_request" or "rpc_response"
Schema string `json:"_schema"` // "rpc-message/v2"
Direction string `json:"direction"` // "IN" or "OUT"
ServerID string `json:"server_id"`
Method string `json:"method,omitempty"`
Error string `json:"error,omitempty"`
AgentSecrecy []string `json:"agent_secrecy,omitempty"`
AgentIntegrity []string `json:"agent_integrity,omitempty"`
Payload json.RawMessage `json:"payload"` // Full sanitized payload as raw JSON
}
JSONLRPCMessage represents a single RPC message log entry in JSONL format
type JSONLUnrecognizedEndpointPassthrough ¶ added in v0.3.25
type JSONLUnrecognizedEndpointPassthrough struct {
Timestamp string `json:"timestamp"`
Event string `json:"event"`
Schema string `json:"_schema"`
Method string `json:"method"`
Path string `json:"path"`
Action string `json:"action"`
Note string `json:"note"`
}
JSONLUnrecognizedEndpointPassthrough records when the proxy forwards an unrecognized endpoint with empty DIFC labels.
type Logger ¶
type Logger struct {
// contains filtered or unexported fields
}
Logger represents a debug logger for a specific namespace.
func ForFile ¶ added in v0.4.2
func ForFile() *Logger
ForFile creates a new Logger with a namespace automatically derived from the calling file's path. The namespace follows the "package:filename" convention where package is the last directory component of the file path and filename is the Go source file name without the .go extension. This eliminates manually maintained namespace strings.
Example: a call from internal/server/unified.go yields namespace "server:unified".
func New ¶
New creates a new Logger for the given namespace. The enabled state is computed at construction time based on the DEBUG environment variable. DEBUG syntax follows https://www.npmjs.com/package/debug patterns:
DEBUG=* - enables all loggers DEBUG=namespace:* - enables all loggers in a namespace DEBUG=ns1,ns2 - enables specific namespaces DEBUG=ns:*,-ns:skip - enables namespace but excludes specific patterns
Colors are automatically assigned to each namespace if DEBUG_COLORS != "0" and stderr is a TTY.
type MarkdownLogger ¶
type MarkdownLogger struct {
// contains filtered or unexported fields
}
MarkdownLogger manages logging to a markdown file for GitHub workflow previews
func (*MarkdownLogger) Close ¶
func (ml *MarkdownLogger) Close() error
Close closes the log file and writes the closing details tag
func (*MarkdownLogger) Log ¶
func (ml *MarkdownLogger) Log(level LogLevel, category, format string, args ...interface{})
Log writes a log message in markdown format with emoji bullet points
type ObservedURLDomainsLogger ¶ added in v0.3.29
type ObservedURLDomainsLogger struct {
// contains filtered or unexported fields
}
ObservedURLDomainsLogger manages unique observed URL domains grouped by server ID.
func (*ObservedURLDomainsLogger) Close ¶ added in v0.3.29
func (l *ObservedURLDomainsLogger) Close() error
func (*ObservedURLDomainsLogger) LogDomains ¶ added in v0.3.29
func (l *ObservedURLDomainsLogger) LogDomains(serverID string, domains []string) error
LogDomains logs unique domains for a server ID.
type RPCMessageDirection ¶
type RPCMessageDirection string
RPCMessageDirection represents whether the message is inbound or outbound
const ( // RPCDirectionInbound represents messages coming into the gateway RPCDirectionInbound RPCMessageDirection = "IN" // RPCDirectionOutbound represents messages going out from the gateway RPCDirectionOutbound RPCMessageDirection = "OUT" )
type RPCMessageInfo ¶
type RPCMessageInfo struct {
Direction RPCMessageDirection // IN or OUT
MessageType RPCMessageType // REQUEST or RESPONSE
ServerID string // Backend server ID or "client" for client messages
Method string // RPC method name (for requests)
PayloadSize int // Size of the payload in bytes
Payload string // First N characters of payload (sanitized)
Error string // Error message if any (for responses)
}
RPCMessageInfo contains information about an RPC message for logging
type RPCMessageType ¶
type RPCMessageType string
RPCMessageType represents the direction of an RPC message
const ( // RPCMessageRequest represents an outbound request or inbound client request RPCMessageRequest RPCMessageType = "REQUEST" // RPCMessageResponse represents an inbound response from backend or outbound response to client RPCMessageResponse RPCMessageType = "RESPONSE" )
func (RPCMessageType) JSONLEvent ¶ added in v0.3.19
func (t RPCMessageType) JSONLEvent() string
JSONLEvent returns the standardized JSONL event name for this RPC message type.
type ServerFileLogger ¶ added in v0.0.102
type ServerFileLogger struct {
// contains filtered or unexported fields
}
ServerFileLogger manages per-serverID log files
func (*ServerFileLogger) Close ¶ added in v0.0.102
func (sfl *ServerFileLogger) Close() error
Close closes all server log files
type SlogHandler ¶
type SlogHandler struct {
// contains filtered or unexported fields
}
SlogHandler implements slog.Handler by wrapping a gh-aw Logger This allows integration with libraries that expect slog.Logger
func NewSlogHandler ¶
func NewSlogHandler(logger *Logger) *SlogHandler
NewSlogHandler creates a new slog.Handler that wraps a gh-aw Logger
func (*SlogHandler) Enabled ¶
Enabled reports whether the handler handles records at the given level. We enable all levels when our logger is enabled.
func (*SlogHandler) Handle ¶
Handle handles the Record. It will only be called when Enabled returns true.
type ToolsData ¶ added in v0.1.1
type ToolsData struct {
// Map of serverID to array of tools
Servers map[string][]ToolInfo `json:"servers"`
}
ToolsData represents the structure of tools.json
type ToolsLogger ¶ added in v0.1.1
type ToolsLogger struct {
// contains filtered or unexported fields
}
ToolsLogger manages logging of MCP server tools to a JSON file
func (*ToolsLogger) Close ¶ added in v0.1.1
func (tl *ToolsLogger) Close() error
Close is a no-op for ToolsLogger (implements closableLogger interface)