Access Log middleware
VextJS has built-in Access Log middleware, which automatically records the method, path, status code, response time and client IP of each HTTP request. This middleware is based on the onion model (after-middleware mode) and outputs a compact line of access log after the request processing is completed.
Basic behavior
Access Log middleware is enabled by default and does not require any configuration to work:
After the request is completed, the terminal output is similar to:
Log format
Access Log uses compact single-line format and presents different output styles in development and production environments:
Development mode (Pretty)
When logger.pretty is true (the default value in the development environment), the built-in pretty formatter will output a readable format; if logger.prettyColor is parsed to enabled, only the level label will be colored:
The log message itself is always a compact single line of text in the format:
Production Schema (JSON)
When logger.pretty is false (the default value in production environments), Vext logger outputs structured JSON:
Each log is a complete line of JSON object, which is easy to parse by log collection systems such as ELK and Loki.
Note: The
requestIdfield is automatically injected by the logger mixin + AsyncLocalStorage (see below) and does not need to be passed in manually in the access-log middleware.
requestId automatic injection
Working principle
VextJS uses AsyncLocalStorage (Node.js's built-in asynchronous context propagation mechanism) to maintain an independent context for each request. The requestId middleware generates a unique ID when the request comes in and stores it in AsyncLocalStorage. All subsequent log output will automatically carry the ID.
Cross-service tracking
In a microservice architecture, requestId can be passed through HTTP headers to achieve cross-service request link tracking:
Middleware execution location
Access Log is located at position 6 of the built-in middleware chain (after response-wrapper), ensuring:
requestIdhas been generated in the previous middleware (req.requestIdis available)- When the onion returns, the handler has been executed (
res.statusCodehas been determined)
Configuration items
Configure via config.accessLog:
enabled
When set to false, the middleware directly calls next(), skipping it with zero overhead.
level
After setting it to 'debug', you can uniformly control whether to output ordinary access logs through the logger.level initial threshold or runtime app.logger.setLevel() in the production environment. 5xx responses are always promoted to error; 4xx responses are only promoted to warn if warnOn4xx: true.
skipPaths
Common uses: exclude high-frequency paths such as health checks, Kubernetes probes, and Prometheus metrics:
skipPathPrefixes
Complementary to exact matching of skipPaths, suitable for skipping entire internal path trees:
slowThreshold
For requests whose response time exceeds this threshold, the log level is automatically raised to warn, and a [SLOW] tag is appended to the message:
logResponseSize
When enabled, log messages will append Content-Length after the IP (if present in the response header):
warnOn4xx
Level mapping:
This is very useful for alarm monitoring in production environments - you can set alarm rules for the error level in the logging system to automatically capture 5xx errors.
Performance optimization
Access Log middleware has made a number of performance optimizations internally:
- Set precomputation —
skipPathsis converted toSetduring initialization, and the search complexity is O(1) - Method pre-binding —
logger.info.bind(logger)is bound during initialization to avoid dynamic search for each request - Quick skip —
return next()immediately whenenabled: false, without any additional overhead - Single-line message — Use string concatenation instead of structured objects to avoid pretty mode expanding fields into multiple lines
TypeScript types
Relationship with log storage
The output of Access Log goes through the unified app.logger (Vext logger), so all the storage solutions described in Log Document are applicable:
- stdout → Cloud — cloud native logging pipeline
- PM2 / systemd + logrotate — drop and rotate during stand-alone deployment
- Filebeat / Fluent Bit → ELK — Collect JSON logs to Elasticsearch
- Docker → Loki — Container log driver or Agent push
- app.setLogger bridging — Plug-in layer is forwarded to external SDK synchronously
If you need to store the access log separately in an independent file, it is recommended to filter by msg, path or level at the log collection layer and then divert the data. When synchronous forwarding is required within the application, app.setLogger() can be used to wrap the current logger.
Next step
- Understand the complete configuration and storage solution of Log System
- See Configuration Document to learn about the environment coverage mechanism
- Understand how requestId and request context works