Skip to main content

structured_log_dio 0.1.0-dev.3 copy "structured_log_dio: ^0.1.0-dev.3" to clipboard
structured_log_dio: ^0.1.0-dev.3 copied to clipboard

StructuredLogDioInterceptor — a dio Interceptor that logs every request, response and failure as structured_log entries, with sensitive headers and query parameters redacted.

structured_log_dio #

CI

Читать на русском.

Logs every request a dio client sends and how it ended — response, error, timeout, cancellation — as structured_log entries.

StructuredLogDioInterceptor is an ordinary dio Interceptor: add it to dio.interceptors, and every call reports through the sinks you have already configured — the console, a file, the in-app log viewer (structured_log_flutter), or a structured_log_server via structured_log_remote_sync.

Features #

  • One line to install — dio.interceptors.add(StructuredLogDioInterceptor())
  • Request and outcome, paired — http_request_id ties a call's two entries together; the outcome carries status_code and duration_ms
  • Levels by status — 2xx/3xx at debug, 4xx at warning, 5xx and failures without a response at error, cancellations at debug; each adjustable or off
  • Secrets stay out by default — headers and bodies are not logged unless asked for; Authorization, cookies and API-key headers are redacted even then, and so are password- and token-like fields in a body; token-like query parameters and URL user info are always redacted
  • Its own category — every entry carries category: 'http', for a LogSink to route and the log viewer to filter on
  • Never breaks a call — a describer or filter that throws costs the entry, not the request

Installation #

Published on pub.dev as a pre-release (0.1.0-dev.2):

dependencies:
  dio: ^5.4.0
  structured_log: ^0.3.0
  structured_log_dio: ^0.1.0-dev.2

Breaking change after 0.1.0-dev.2: with a body turned on, a string body whose content type is neither JSON nor a form is now written only by its size, <N chars>, instead of as it is. logUnrecognizedBodies: true brings the old behaviour back. See Keeping secrets out of the log.

Quick Start #

import 'package:dio/dio.dart';
import 'package:structured_log/structured_log.dart';
import 'package:structured_log_dio/structured_log_dio.dart';

Future<void> main() async {
  StructlogConfiguration.configure(
    sinks: [LogSink(name: 'console', output: coloredConsoleOutput)],
  );

  final dio = Dio(BaseOptions(baseUrl: 'https://api.example.com'))
    ..interceptors.add(StructuredLogDioInterceptor());

  await dio.get('/items', queryParameters: {'access_token': 's3cr3t'});
}
DEBUG: http_request  {"category":"http","http_request_id":1,"method":"GET","url":"https://api.example.com/items?access_token=REDACTED"}
DEBUG: http_response {"category":"http","http_request_id":1,"method":"GET","url":"https://api.example.com/items?access_token=REDACTED","status_code":200,"duration_ms":59}

example/main.dart runs offline against a server it starts itself (dart run example/main.dart).

Add the interceptor last. Interceptors run in order, so the last one logs the request that actually leaves — with the headers the others added — and sees each response before any of them can turn it into something else.

What gets logged #

Entry When Fields
http_request the request is about to be sent http_request_id, method, url; request_headers, request_body if enabled
http_response a response arrived and validateStatus accepted it the above, status_code, duration_ms; response_headers, response_body if enabled
http_error anything else: a rejected status, a timeout, a refused connection, a cancellation the above, status_code if there was a response, error_type (the DioExceptionType), error

The level of an outcome follows its status code wherever it arrives from, so a 404 is a warning whether validateStatus accepted it or not. error is left out for badResponse: dio's message for it only restates the status code.

http_request_id counts calls per interceptor instance, starting at 1.

Keeping secrets out of the log #

  • Headers and bodies are off by default. logHeaders, logRequestBody and logResponseBody turn them on.

  • With headers on, the values of defaultRedactedHeaders — authorization, proxy-authorization, cookie, set-cookie, x-api-key — become REDACTED. Pass redactedHeaders to change the set (lower-case names; compared case-insensitively).

  • Query parameters named in defaultRedactedQueryParameters — access_token, refresh_token, id_token, token, api_key, apikey, password, client_secret — are always redacted; pass redactedQueryParameters to change the set. User info in the URL (https://user:pass@host) is always dropped.

  • Bodies, once on, are redacted before they are written. Fields named in redactedBodyFields become REDACTED, at any depth and regardless of case. The default, defaultRedactedBodyFields, is structured_log's own defaultSensitiveKeys — password, token, access_token, client_secret, api_key, authorization and their spelling variants — so a body and a log entry are redacted by one list. What gets redacted depends on the body:

    • a map or a list — redacted as it is;
    • a string whose content type is JSON (application/json, *+json) or a form (application/x-www-form-urlencoded) — parsed, redacted and written back; one that does not parse is written as <unparseable body>, since what cannot be parsed cannot be redacted;
    • a string of any other type — only its length, <N chars>: there is no knowing where a secret sits in text of unknown shape. logUnrecognizedBodies: true writes such strings as they are.

    The result is then JSON-encoded and cut to 1000 characters. A describeBody of your own receives the body already redacted; returning null from it leaves the field out. To redact more than the defaults, spread them into your own set — passing a set replaces the defaults rather than adding to them:

StructuredLogDioInterceptor(
  logRequestBody: true,
  logResponseBody: true,
  redactedBodyFields: {...defaultRedactedBodyFields, 'otp', 'pin'},
);

Configuration #

StructuredLogDioInterceptor(
  // Which outcomes are logged, and at what level; null turns one off.
  levels: const HttpLogLevels(request: null, clientError: LogLevel.info),
  // Leave health checks out — both of a call's entries.
  filter: (options) => options.path != '/health',
  category: 'network',
);

Raw bytes and streams are summarised rather than dumped (<42 bytes>, <stream>, <FormData: 2 fields, 0 files>).

API Reference #

Symbol Description
StructuredLogDioInterceptor({logger, loggerName, category, levels, logHeaders, logRequestBody, logResponseBody, redactedHeaders, redactedQueryParameters, describeBody, filter, redactedBodyFields, logUnrecognizedBodies}) The interceptor. Without logger it calls getLogger(loggerName) (dio) on every entry, so a later StructlogConfiguration.configure reaches it too. category: null binds no category.
HttpLogLevels({request, success, clientError, serverError, failure, cancel}) A LogLevel? per outcome; null turns it off.
HttpBodyDescriber Object? Function(Object? body) — turns a body, already redacted, into an entry value; null omits the field.
describeHttpBody(body) The default describer: strings as they are, maps and lists JSON-encoded, bytes/streams/FormData summarised, cut to defaultHttpBodyMaxLength (1000) characters.
redactedBodyFields Body field names whose values become REDACTED, case-insensitively, at any depth. Defaults to defaultRedactedBodyFields; a set passed here replaces it.
logUnrecognizedBodies Whether a string body that is neither JSON nor a form is written as it is. false by default: it is written as <N chars>.
defaultRedactedHeaders, defaultRedactedQueryParameters, defaultRedactedBodyFields, redactedValue The default redaction sets and the value (REDACTED) that replaces what they match. defaultRedactedBodyFields is structured_log's defaultSensitiveKeys.

The rest of the structured_log family:

Core

  • structured_log — structured JSON logging with context binding, processors and multi-sink routing

In-app log viewer

Shipping logs to a server

Integrations

License #

See LICENSE.

0
likes
0
points
790
downloads

Documentation

Documentation

Publisher

unverified uploader

Weekly Downloads

StructuredLogDioInterceptor — a dio Interceptor that logs every request, response and failure as structured_log entries, with sensitive headers and query parameters redacted.

Homepage
Repository (GitHub)
View/report issues

Topics

#logging #dio #http #interceptor #network

License

unknown (license)

Dependencies

dio, structured_log

More

Packages that depend on structured_log_dio