ML-158: task research and plan

This commit is contained in:
Claudio Ortolina
2026-05-03 15:28:02 +01:00
parent 9fda537bf9
commit 29bedcd028
2 changed files with 268 additions and 0 deletions
@@ -0,0 +1,78 @@
---
id: doc-3
title: 'Research: Force production logs to single-line format'
type: other
created_date: '2026-05-03 13:53'
updated_date: '2026-05-03 14:23'
---
# Research: Force production logs to single-line format
## Current state
**Config** (`config/config.exs`):
```elixir
config :logger, :default_formatter,
format: "$time $metadata[$level] $message\n",
metadata: [:request_id]
```
**Override** (`config/prod.exs`):
```elixir
config :logger, level: :info
```
**Log sources in prod**:
| Source | Produces | Problem |
|---|---|---|
| `Phoenix.Logger` (telemetry) | `GET /health` + `Sent 200 in Xms` | Two separate lines for one request — can't reverse |
| `Phoenix.Logger` (telemetry) | `CONNECTED TO Phoenix.LiveView.Socket...` | One event with embedded `\n` — 4+ lines |
| Custom `Logger.info/error/...` | Varies | Some may be multi-line |
| OTP / stack traces | Crash reports | Multi-line |
`Phoenix.Logger` is auto-attached by Phoenix.Endpoint and handles telemetry events including `[:phoenix, :endpoint, :start]`, `[:phoenix, :endpoint, :stop]`, and `[:phoenix, :socket_connected]`.
## Chosen approach: Option 2 (comprehensive)
1. **Disable Phoenix.Logger**`config :phoenix, :logger, false` in prod
2. **Add Logster v2**`Logster.attach_phoenix_logger()` for single-line HTTP request logging (logfmt format)
3. **Custom telemetry handler** — for `[:phoenix, :socket_connected]` LiveView handshakes (if not covered by Logster)
4. **Custom Logger.Formatter** — safety net replacing `\n``\\n` in all remaining messages
5. **Code audit** — fix multi-line Logger calls in project code
### Why Logster v2 over v1
v2 (`~> 2.0.0-rc.5`) uses `Logster.attach_phoenix_logger()` in `application.ex` instead of replacing a plug in the endpoint. This is the modern approach that works with Phoenix's telemetry-based logging architecture. It outputs logfmt (`key=value`) format by default, merging the `GET /path` and `Sent 200` lines into one.
### Architecture impact
| Touchpoint | Change |
|---|---|
| `config/prod.exs` | Add `config :phoenix, :logger, false` + Logster config + formatter config |
| `lib/music_library/application.ex` | Add conditional `Logster.attach_phoenix_logger()` |
| `lib/music_library_web/telemetry_log_handler.ex` | **New module** — handles socket_connected telemetry |
| `lib/music_library/logger/single_line_formatter.ex` | **New module** — Logger.Formatter format function |
| `mix.exs` | Add `{:logster, "~> 2.0.0-rc.5"}` |
| Docs | Update `docs/production-infrastructure.md` with logging config |
### Performance
- Logster: one telemetry handler invocation per request, logfmt formatting is string interpolation — negligible overhead
- Custom formatter: one `String.replace/3` per log event, Logger already truncates messages — negligible
- No CPU or memory concerns at the log volume of a personal app
### Dependencies
- `logster ~> 2.0.0-rc.5` (1.9M downloads, MIT license, active maintenance)
### Cost
- None — no paid services involved
---
## Questions resolved
1. **Newline style**: Replace `\n` with `\\n` (escaped, traceable)
2. **Scope**: Prod-only; dev keeps current multi-line format for readability
3. **Module naming**: `MusicLibrary.Logger.SingleLineFormatter` and `MusicLibraryWeb.TelemetryLogHandler`