mihaelamj/openapiloggingmiddleware
A flexible, configurable logging middleware for OpenAPI client and server implementations with support for console, file, and OSLog logging.
Features
- ✅ Dual Parameter System: Separate
appNameandlogPrefixfor clean file naming and formatted console output - ✅ Client & Server Support: Works with both
ClientMiddlewareandServerMiddleware - ✅ Configurable Body Logging: Control how much request/response body data to log
- ✅ Multiple Log Handlers: Simultaneous console (stream), JSON file, and OSLog logging
- ✅ OSLog Integration: Native Apple unified logging system support (macOS 11+, iOS 14+)
- ✅ Automatic File Naming: Generates clean filenames from app name and prefix
- ✅ Pluggable Handlers (v1.2.0): Ship log events to any sink via
ObserverLogHandler - ✅ Per-Event Log Levels (v1.2.0): Configure
requestLogLevel,responseLogLevel,errorLogLevelindependently
Usage
Basic Usage
import OpenAPILoggingMiddleware
// Client logging
let clientMiddleware = LoggingMiddleware(
appName: "NSSpainAPI",
logPrefix: "🚚 APIClient: "
)
// Server logging
let serverMiddleware = await LoggingMiddleware(
appName: "NSSpainAPI",
logPrefix: "🖥️ ApiServer: "
)Advanced Configuration
let middleware = LoggingMiddleware(
logger: customLogger, // Optional custom logger
bodyLoggingConfiguration: .upTo(maxBytes: 2_000_000), // Log bodies up to 2MB
appName: "MyApp", // App identifier for files
logPrefix: "🔧 Service: ", // Console output prefix
requestLogLevel: .debug, // v1.2.0+: per-event level
responseLogLevel: .debug,
errorLogLevel: .error // v1.2.0+: errors at .error by default
)Extensibility (v1.2.0+)
All built-in handlers are public. Plug a custom sink (admin panel, WebSocket broadcast, analytics pipeline, test harness) alongside the defaults using Apple's Logging.MultiplexLogHandler plus the new ObserverLogHandler:
import Logging
import OpenAPILoggingMiddleware
let logger = Logger(label: "my-app") { label in
MultiplexLogHandler([
PrefixedStreamLogHandler(label: label, logPrefix: "🖥️ "),
ObserverLogHandler(label: label) { event in
// Forward every log event anywhere you like:
MyDashboardBuffer.shared.push(event)
}
])
}
let middleware = LoggingMiddleware(
logger: logger,
appName: "MyApp",
logPrefix: "🖥️ "
)You can also start from the built-in defaults and layer on top:
let base = LoggingMiddleware.defaultLogger(logPrefix: "🖥️ ")
// wrap via MultiplexLogHandler if you need to add your own handlerFile Naming
The middleware automatically generates clean, organized log file names:
| appName | logPrefix | File Names | |---------|-----------|------------| | "NSSpainAPI" | "🚚 APIClient: " | _NSSpainAPI_APIClient.json, _NSSpainAPI_APIClient.log | | "NSSpainAPI" | "🖥️ ApiServer: " | _NSSpainAPI_ApiServer.json, _NSSpainAPI_ApiServer.log | | "MyApp" | "Client: " | _MyApp_Client.json, _MyApp_Client.log | | nil | "🚚 APIClient: " | _APIClient.json, _APIClient.log | | nil | "" | _OpenAPILog.json, _OpenAPILog.log |
File Naming Rules:
- With both appName and logPrefix:
<appName><cleanPrefix>.<ext> - With appName only:
_<appName>.<ext> - With logPrefix only:
_<cleanPrefix>.<ext> - Neither provided:
_OpenAPILog.<ext>(default)
Clean names are generated by:
- Trimming whitespace
- Removing spaces from prefix
- Filtering to ASCII letters and numbers (removes emojis)
Log Output
Console Output (Stream)
Uses the logPrefix as-is for visual distinction:
🚚 APIClient: `method` = `GET`
🚚 APIClient: `path` = `/user/me`
🚚 APIClient: `statusCode` = `200`JSON File Output
Structured JSON logs saved to Documents directory:
[
{
"timestamp": "16.10.2025. 14:30:45",
"method": "GET",
"path": "/user/me",
"statusCode": "200",
"responseBody": "{...}"
}
]OSLog Output (macOS 11+, iOS 14+)
Native Apple unified logging system integration. Logs appear in:
- Console.app on macOS
- Xcode Console during development
- System log database for persistent storage
Subsystem: com.openapi Category: logging-middleware
Viewing OSLog Output
Real-Time Log Streaming
Method 1: Terminal (Recommended for Development)
Open Terminal and run:
# Stream ALL logs from the middleware in real-time
log stream --predicate 'subsystem == "com.openapi"' --level debugThis will show logs as they happen - you'll see each API request/response immediately.
Additional real-time filters:
# Filter by specific prefix (e.g., only APIClient logs)
log stream --predicate 'subsystem == "com.openapi" AND eventMessage CONTAINS "APIClient"' --level debug
# Show only errors in real-time
log stream --predicate 'subsystem == "com.openapi"' --level error
# Filter by specific HTTP method
log stream --predicate 'subsystem == "com.openapi" AND eventMessage CONTAINS "GET"' --level debugMethod 2: Console.app (GUI)
For a visual real-time log viewer:
- Open Console.app (press
⌘+Space, type "Console", press Enter) - In the left sidebar, select your Mac under "Devices"
- In the search field (top-right), type:
subsystem:com.openapi - Click the "Start" button to begin streaming logs in real-time
- Logs will appear live as your app makes API calls
Tip: Keep Console.app open while running your app to see all logs in real-time with syntax highlighting!
Historical Logs
View past logs in Terminal:
# Show logs from the last hour
log show --predicate 'subsystem == "com.openapi"' --last 1h
# Show logs with specific text
log show --predicate 'subsystem == "com.openapi" AND eventMessage CONTAINS "GET"' --last 30m
# Export logs to a file
log show --predicate 'subsystem == "com.openapi"' --last 1d --style json > logs.jsonLog Level Mapping:
| swift-log Level | OSLog Type | Console.app Display | |----------------|-----------|---------------------| | .trace | .debug | Debug | | .debug | .debug | Debug | | .info | .info | Info | | .notice | .default | Default | | .warning | .error | Error | | .error | .error | Error | | .critical | .fault | Fault |
Privacy & Performance:
- OSLog is highly optimized for performance
- Logs are stored in a compressed binary format
- Automatic log rotation and retention policies
- System-level privacy controls for sensitive data
Architecture
The middleware uses Apple's Logging.MultiplexLogHandler to direct log output to multiple destinations simultaneously. By default, it's configured with:
PrefixedStreamLogHandler: Prints formatted logs to the console (stdout). (Renamed fromStreamLogHandlerin v1.2.0 to avoid collision with swift-log's ownStreamLogHandler.)JSONFileLogHandler: Saves structured JSON logs to a file in the app's Documents directory.OSLogHandler: Sends logs to Apple's unified logging system (macOS 11+, iOS 14+).
As of v1.2.0 all four handlers (plus the new ObserverLogHandler) are public, so you can reuse them when composing your own Logger. See Extensibility above.
This architecture makes it easy to:
- Monitor logs in real-time during development (console & OSLog)
- Persist structured logs for analysis (JSON files)
- Integrate with system-level logging tools (Console.app,
logcommand) - Debug production issues using native Apple tools
Body Logging Policy
Control how request/response bodies are logged:
// Never log bodies (for sensitive data)
.never
// Log bodies up to specified size (default: 2MB)
.upTo(maxBytes: 1024 * 1024 * 2)Log Metadata
Each log entry includes:
- HTTP method
- Request path
- Base URL and full path
- Request/response headers (JSON format)
- Request/response body (based on policy)
- Operation ID
- Status code and reason
- Error information (if failed)
- Unique identifier per request
Log Destinations
File Locations
Log files are saved to the system Documents directory:
- iOS/macOS:
~/Documents/ - JSON logs:
<appName><prefix>.json
Console Output
- Stream logs: Output to
stdout(Xcode Console, Terminal)
OSLog (macOS 11+, iOS 14+)
- System database: Managed by
logddaemon - Location:
/var/db/diagnostics/(system-managed, not user-accessible) - Access: Use
Console.apporlogcommand (see Viewing OSLog Output)
Example Integration
ApiClient
self.loggingMiddleware = LoggingMiddleware(
appName: "NSSpainAPI",
logPrefix: "🚚 APIClient: "
)
self.client = Client(
serverURL: serverURL,
transport: transport,
middlewares: [loggingMiddleware, authMiddleware]
)ApiServer
let loggingMiddleware = await LoggingMiddleware(
appName: "NSSpainAPI",
logPrefix: "🖥️ ApiServer: "
)
try handler.registerHandlers(
on: transport,
serverURL: serverURL,
middlewares: [loggingMiddleware]
)Thread Safety
The LoggingMiddleware is an actor, ensuring thread-safe operation across concurrent requests.
Dependencies
swift-openapi-runtime- OpenAPI runtime supportswift-log- Logging backendHTTPTypes- HTTP types
Package Metadata
Repository: mihaelamj/openapiloggingmiddleware
Default branch: main
README: README.md