Auditing
Request traffic logging records per-request metadata (timing, status, user, client address, headers and optionally bodies) to file or SQLite storage.
Configuration
| Setting | Description | Default |
|---|---|---|
Enabled |
Enables traffic logging | false |
QueueCapacity |
Max queued log entries | 10000 |
StorageType |
Storage type: "file" or "sqlite" | "file" |
SqlitePath |
Path to SQLite database | "log/traffic_logs.db" |
LogDirectory |
Directory for log files | "log/traffic" |
MaxFileSizeMB |
Max size per log file | 50 |
MaxFileCount |
Number of files to retain | 5 |
FilePrefix |
Prefix for log filenames | "proxy_traffic_" |
BatchSize |
Entries per batch write | 100 |
FlushIntervalMs |
Write interval in ms | 1000 |
IncludeRequestBodies |
Capture request bodies | false |
IncludeResponseBodies |
Capture response bodies | false |
MaxBodyCaptureSizeBytes |
Max body size to capture | 4096 |
CaptureHeaders |
Capture request headers | true |
EnableInfoLogging |
Log at INFO level | true |
Storage types
File storage
With StorageType: "file", entries are written to rotating JSON files:
log/traffic/
├── proxy_traffic_20240120_103015.json
├── proxy_traffic_20240120_083045.json
└── proxy_traffic_20240119_154530.json- One JSON object per line
- Rotation at
MaxFileSizeMB - The oldest files beyond
MaxFileCountare deleted - File names contain the creation time
SQLite storage
With StorageType: "sqlite", entries are written to this table:
CREATE TABLE TrafficLogs (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
Timestamp TEXT NOT NULL,
Method TEXT NOT NULL,
Path TEXT NOT NULL,
QueryString TEXT,
Environment TEXT,
EndpointName TEXT,
TargetUrl TEXT,
StatusCode INTEGER,
RequestSize INTEGER,
ResponseSize INTEGER,
DurationMs INTEGER,
Username TEXT,
ClientIp TEXT,
TraceId TEXT NOT NULL,
RequestHeaders TEXT,
RequestBody TEXT,
ResponseBody TEXT
);
CREATE INDEX idx_timestamp ON TrafficLogs (Timestamp);Log entry format
{
"Id": 12345,
"Timestamp": "2024-01-20T10:30:15Z",
"Method": "GET",
"Path": "/api/500/Products",
"QueryString": "?$top=10",
"Environment": "prod",
"EndpointName": "Products",
"TargetUrl": "http://localhost:8020/services/Exact.Entity.REST.EG/Product",
"StatusCode": 200,
"RequestSize": 0,
"ResponseSize": 2048,
"DurationMs": 45,
"Username": "api-user",
"ClientIp": "192.168.1.100",
"TraceId": "a1b2c3d4",
"RequestHeaders": {
"Accept": "application/json",
"Authorization": "[REDACTED]",
"User-Agent": "MyApp/1.0"
},
"RequestBody": null,
"ResponseBody": null
}Id is present in SQLite storage only. TargetUrl is set for proxy requests. Body fields are null unless body capture is enabled.
Security features
Header sanitization
Redacted header values: Authorization, Cookie, X-API-Key, API-Key, Password, X-Auth-Token, Token, Secret, Credential, Access-Token, X-Access-Token, and every header and query parameter name declared in an environment's Authentication.Methods.
Body capture controls
Body capture is disabled by default, limited to MaxBodyCaptureSizeBytes (longer bodies end with ...) and applies to JSON and XML content only.
Storage access
Store traffic logs outside web-served directories, with file permissions limited to the Portway process.
Performance considerations
Entries are queued and written in background batches. Tuning for high volume:
| Setting | Recommendation |
|---|---|
IncludeRequestBodies / IncludeResponseBodies |
Disabled outside debugging |
BatchSize |
Higher (e.g. 500) for fewer writes |
FlushIntervalMs |
Higher (e.g. 5000) when I/O is the bottleneck |
QueueCapacity |
Higher when the application log reports a full queue |
StorageType |
file has higher throughput than sqlite |
Querying traffic logs
File storage queries
SQLite queries
-- Top 10 slowest requests
SELECT
Timestamp,
Method,
Path,
DurationMs,
StatusCode
FROM TrafficLogs
ORDER BY DurationMs DESC
LIMIT 10;
-- Request count by endpoint
SELECT
EndpointName,
COUNT(*) as RequestCount,
AVG(DurationMs) as AvgDuration,
MAX(DurationMs) as MaxDuration
FROM TrafficLogs
GROUP BY EndpointName
ORDER BY RequestCount DESC;Troubleshooting
| Symptom | Check |
|---|---|
| Logs not written | Enabled: true in config; write permissions on LogDirectory / SqlitePath; check application logs |
| Missing entries | Queue may be full, increase QueueCapacity; verify FlushIntervalMs is not too high |
| High performance impact | Disable body capture; increase BatchSize and FlushIntervalMs; switch to file storage |
| Disk filling up | Reduce MaxFileCount; reduce MaxBodyCaptureSizeBytes; disable body capture |
| SQLite errors | Check file permissions; ensure path directory exists; validate with sqlite3 log/traffic_logs.db .tables |
Portway