Maven Central Scala 3.3 License: MIT

Http4s Better Logger (h4sbl)

h4sbl is a Scala 3 library that provides enhanced logging middleware for http4s applications. It offers colorful, configurable, and comprehensive logging for HTTP operations.

The standard http4s logger is functional but limited. h4sbl provides a cleaner, more informative logging experience with color-coded output, sensitive header redaction, and log level-aware verbosity.

Features

  • Colorful Output - Color-coded HTTP methods, status codes, and headers for easy visual parsing
  • Configurable - Full control over colors, secret redaction, and body logging
  • Log Level Aware - Automatically adjusts verbosity based on your logger configuration
  • Header Redaction - Automatically redacts sensitive headers (Authorization, Cookie, etc.) with support for custom headers
  • URI Redaction - Redacts sensitive query parameter values (tokens, API keys, passwords) when secret redaction is enabled
  • Body Capture - Optionally logs request and response bodies at TRACE level with a sanitization hook
  • Minimal Boilerplate - Simple API that wraps your existing http4s client

Installation

Add the following dependencies to your build.sbt:

libraryDependencies ++= Seq(
  "com.colofabrix.scala" %% "h4sbl"         % "<see Maven Central badge>",
  "org.http4s"           %% "http4s-client" % <version>,  // Required peer dependency
  "org.typelevel"        %% "cats-effect"   % <version>,  // Required peer dependency
)

Note: h4sbl uses Provided scope for http4s and Cats Effect, giving you full control over the versions in your project.

Quick Start

Basic Usage

Wrap your http4s client with the logging middleware:

import cats.effect.*
import com.colofabrix.scala.http4s.middleware.betterlogger.*
import org.http4s.ember.client.EmberClientBuilder

object MyApp extends IOApp.Simple:

  def run: IO[Unit] =
    EmberClientBuilder
      .default[IO]
      .build
      .map(ClientLogger(_))  // Wrap with logging
      .use { client =>
        client.expect[String]("https://httpbin.org/get").flatMap(IO.println)
      }

With Secret Redaction Control

Control whether sensitive data is redacted in logs:

import com.colofabrix.scala.http4s.middleware.betterlogger.*

// Redact secrets (default behavior)
val safeLoggingClient = ClientLogger(httpClient)

// Show everything (useful for debugging)
val debugClient = ClientLogger.withConfig(LogConfig(redactSecrets = false))(httpClient)

When redactSecrets = true (the default), the following are automatically redacted:

  • Headers: Authorization, Cookie, Set-Cookie (built-in via http4s Headers.SensitiveHeaders) plus any custom headers specified in sensitiveHeaders
  • URI query parameters: Parameter values matching the built-in set (token, api_key, password, secret, etc.) or custom names specified in sensitiveQueryParams

Full Configuration

For complete control over logging behavior:

import com.colofabrix.scala.http4s.middleware.betterlogger.*
import org.typelevel.ci.CIString

val config =
  LogConfig(
    redactSecrets = true,
    sensitiveHeaders = Set(CIString("X-Api-Key"), CIString("X-Auth-Token")),
    sensitiveQueryParams = Set("my_secret_param"),
    colors = LogColors.default,
    logRequestBody = true,
    logResponseBody = true,
    sanitizeBody = body => body.replaceAll("\"password\"\\s*:\\s*\"[^\"]*\"", "\"password\": \"<REDACTED>\""),
  )

val loggingClient = ClientLogger.withConfig(config)(httpClient)

Body Sanitization

When logging bodies at TRACE level, you can provide a sanitizeBody function to redact sensitive data before it appears in logs. The function receives the raw body string and returns the sanitized version. Body sanitization is only applied when redactSecrets = true:

import com.colofabrix.scala.http4s.middleware.betterlogger.*

val config = LogConfig(
  sanitizeBody = body =>
    body
      .replaceAll("\"password\"\\s*:\\s*\"[^\"]*\"", "\"password\": \"<REDACTED>\"")
      .replaceAll("\"token\"\\s*:\\s*\"[^\"]*\"", "\"token\": \"<REDACTED>\"")
)

val loggingClient = ClientLogger.withConfig(config)(httpClient)

Note: Body sanitization is applied at the string level. For complex formats (JSON, XML, protobuf), consider sanitizing upstream at the application layer before the body reaches the logger.

Disable Colors

For log files or environments that don't support ANSI colors:

import com.colofabrix.scala.http4s.middleware.betterlogger.*

val config = LogConfig(colors = LogColors.noColors)
val loggingClient = ClientLogger.withConfig(config)(httpClient)

API Reference

ClientLogger

The main entry point for creating a logging middleware.

Method Description
apply(client) Wrap client with default configuration
withConfig(config)(client) Wrap client with full configuration

LogConfig

Configuration case class for logging behavior.

Parameter Type Default Description
redactSecrets Boolean true Master switch for all redaction (headers, query params, body)
sensitiveHeaders Set[CIString] Set.empty Header names to redact (replaces built-in set when non-empty)
sensitiveQueryParams Set[String] Set.empty Query param names to redact (replaces built-in set when non-empty)
colors LogColors LogColors.default Color scheme for console output
logRequestBody Boolean true Log request bodies (only at TRACE level)
logResponseBody Boolean true Log response bodies (only at TRACE level)
sanitizeBody String => String identity Transform function applied to body strings before logging

Built-in sensitive sets:

  • Headers (from http4s Headers.SensitiveHeaders): Authorization, Cookie, Set-Cookie
  • Query parameters (LogConfig.SensitiveQueryParams): api_key, apikey, api-key, token, access_token, access-token, refresh_token, refresh-token, password, passwd, secret, client_secret, client-secret, private_key, private-key

When sensitiveHeaders or sensitiveQueryParams are non-empty, they replace the built-in set entirely. They are not additive. To extend the built-in set, include all desired names.

LogColors

Color scheme configuration for log output.

Parameter Default Description
httpVersion White Color for HTTP version (e.g., HTTP/1.1)
safeMethod Green Color for GET, HEAD, OPTIONS
unsafeMethod Yellow Color for POST, PUT, DELETE, etc.
uri Magenta + Bold Color for request URI
headers Blue Color for headers section
body White Color for body content
successStatus Green Color for 1xx, 2xx, 3xx responses
clientErrorStatus Yellow Color for 4xx responses
serverErrorStatus Red Color for 5xx responses

Presets:

  • LogColors.default - Full ANSI color support
  • LogColors.noColors - Plain text output

Log Level Behavior

h4sbl adjusts its output based on the configured log level:

Log Level Behavior
TRACE Full output: method, URI, headers, and bodies
DEBUG Method, URI, and headers (no bodies)
INFO+ Minimal or no logging

Advanced Usage

Custom Color Scheme

Create a custom color scheme for your logs:

import scala.Console.*

val customColors =
  LogColors(
    httpVersion = CYAN,
    safeMethod = BLUE,
    unsafeMethod = RED,
    uri = s"$WHITE$BOLD",
    headers = YELLOW,
    body = WHITE,
    successStatus = GREEN,
    clientErrorStatus = MAGENTA,
    serverErrorStatus = s"$RED$BOLD",
    reset = RESET,
  )

val config = LogConfig(colors = customColors)
val loggingClient = ClientLogger.withConfig(config)(httpClient)

Integration with Logback

Configure your logback.xml to control logging verbosity:

<configuration>
  <!-- Show full details including bodies -->
  <logger name="com.colofabrix.scala.http4s.middleware.betterlogger" level="TRACE"/>

  <!-- Or just headers, no bodies -->
  <logger name="com.colofabrix.scala.http4s.middleware.betterlogger" level="DEBUG"/>
</configuration>

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

h4sbl is released under the MIT license. See LICENSE for details.

Author

Fabrizio Colonna

See Also

  • http4s - Typeful, functional HTTP for Scala
  • Cats Effect - The pure asynchronous runtime for Scala
  • log4cats - Logging for Cats Effect