# First logger The quick start for Atlas Log and the project behind the tutorial in the [Atlas Log guide](https://youseful.software/delphi/atlas-log.html). A console program that sets up one `TAtlasLogger` with five sinks, logs a short script, then reads its own output back and checks it. ## What it demonstrates - A `TAtlasLogger` that owns its sinks, with `MinLevel` on the logger (`llDebug`) and on individual sinks. - `TAtlasMemorySink`: every event kept in memory and inspected through `Snapshot`, `TAtlasLogEvent.PropertyValue` and the sequence numbers. - `TAtlasConsoleSink` with a custom `Pattern`, showing warnings and above (errors go to standard error). - `TAtlasDebugSink`: the same events for the IDE's event log or any `OutputDebugString` viewer. - `TAtlasFileSink` twice, in a folder under `%TEMP%`: a text file rotated at 512 bytes (`MaxBytes`, `MaxFiles`), and a JSON-lines file (`Layout := loJson`). - Message templates (`'Order {id} placed by {customer} for {total}'`) whose holes become properties, a channel (`Log.Channel('orders')`), a scope (`BeginScope`), a failure (`Failure`) and a timed scope (`Time`). - Reading a log file while the sink still holds it open. ## Build and run Open `FirstLogger.dpr` in Delphi 13; the IDE creates the project file. Add the Atlas Log `src` folder to the project's search path, then build and run for Win32 or Win64. No packages need to be installed. The program needs no input. It checks its own results and stops with an error if any of them differs from the output below. The program needs no input and removes its temporary folder when it ends. ## Expected output Every check prints an `ok:` line; the program ends with `All checks passed.` and exit code 0. Any failed check prints `Exception: Check failed: ...` and sets exit code 1. Paths, the thread id, the timestamp and the elapsed milliseconds differ on your machine: ``` Logging... console: [WRN] orders Stock for AX-7 is low: 3 left console: [ERR] orders Could not archive the order | EInOutError: Disk quota exceeded Memory sink: ok: 26 events reached the memory sink, the debug event included ok: the template filled its holes and kept them as properties ok: the failure kept the exception apart from the message ok: the timer named the scope and reported its duration ok: no sink failed Text file C:\Users\you\AppData\Local\Temp\AtlasLogFirstLogger\app.log: ok: full files were rolled into 2 archives ok: all 25 events at info and above are in the text files, the debug event is not ok: empty tokens leave no double spaces ok: category, scope and properties are on the line ok: the exception follows the message ok: the newest line is last in the active file [INF] [import] Imported row 17 of 20 {row=17, rows=20} [INF] [import] Imported row 18 of 20 {row=18, rows=20} [INF] [import] Imported row 19 of 20 {row=19, rows=20} [INF] [import] Imported row 20 of 20 {row=20, rows=20} [INF] [import] import finished in 2 ms {scope=import, elapsed_ms=2} JSON file C:\Users\you\AppData\Local\Temp\AtlasLogFirstLogger\app.jsonl: ok: one JSON object per event {"ts":"2026-09-22T01:37:43.606Z","seq":3,"level":"info","category":"orders","thread":52800,"scope":"checkout","msg":"Order 1042 placed by Contoso for 1250.5","template":"Order {id} placed by {customer} for {total}","props":{"id":"1042","customer":"Contoso","total":"1250.5"}} ok: the JSON object keeps message, template, scope and properties apart, with a UTC time ok: the exception is a nested object All checks passed. ``` The error line goes to standard error. A console shows it in order, as above; when the output is redirected to a file it may appear separately. ## Adapting it Change `Folder` to your application's log folder, drop the checks, and keep the sink setup. Raise `MaxBytes` to a realistic size (for example `10 * 1024 * 1024`) and set `MaxFiles` to the number of archives to keep. To log from a form instead, create the logger and sinks with the form as owner and keep the `TAtlasLogChannel` values in fields.