1
0
mirror of https://github.com/coturn/coturn.git synced 2026-10-24 00:08:57 +03:00
Files
coturn/docker
Pavel Punsky 62662ec53e Log format: ISO-8601 timestamp by default, no thread id, space delimiter (#2031)
## What

Makes the default log line parseable by a log shipper with no
configuration. Rebased on `master` (`441d3e9c`, which now includes
#2030).

Before:
```
0: (18446744073709551615): INFO: Listener address to use: 127.0.0.1
```
After:
```
2026-08-02T17:32:31.297-0700 INFO Listener address to use: 127.0.0.1
```

Two commits:

| Commit | Change |
|---|---|
| `Cache the rendered log timestamp per thread, add millisecond
precision` | perf + sub-second resolution |
| `Log format: ISO-8601 by default, drop thread id, space delimiter` |
the format change itself |

## Why

**ISO-8601 by default.** The previous default was a counter of seconds
since process start — no wall-clock time at all, so nothing downstream
can order or window on it. `--new-log-timestamp` now also honours its
boolean argument; it previously ignored the value and could only be
turned *on*, so with the default flipped there would have been no way
back. `--new-log-timestamp=false` restores the counter.

**Thread id removed.** It was emitted as a bare unlabelled `(N)`,
indistinguishable from any parenthesised number in a message body.
Worse, it was gated on `#ifdef SYS_gettid` — a test for whether the
*constant* exists, not whether the syscall does what was intended. macOS
defines `SYS_gettid` as a different syscall, so the call failed with
`ESRCH` and every line on every macOS build carried
`(18446744073709551615)`, i.e. `(unsigned long)(pid_t)-1`:

```
SYS_gettid defined = 286
syscall(SYS_gettid) = -1  errno=3 (No such process)
as (unsigned long)(pid_t)r = 18446744073709551615
```

Dropping it also removes the deprecated `syscall(2)` use on macOS.

**Space delimiter.** `:` cannot delimit anything a parser can rely on —
message bodies are full of it (`realm <north.gov> user <>: ...`). These
two changes are coupled: the ISO timestamp emitted *no* trailing
separator (the `(tid): ` supplied it), so removing the thread id alone
would have produced `...-0700INFO`. The renderer now emits only the
timestamp and the caller adds one space.

**Millisecond precision** (first commit). Log shippers need sub-second
resolution to order records within a second, which a busy relay produces
in bulk. `strftime()` has no sub-second conversion, so `%f` is expanded
to milliseconds (`%%f` is left alone) and the default format is
`%FT%T.%f%z`.

**Timestamp caching** (first commit). Everything down to the second only
changes once a second, but was re-rendered per line — and
`localtime_r()` takes a lock inside libc, so relay threads serialised on
it and per-line cost *grew* with thread count. Now cached in
thread-local storage keyed on the second, with only the millisecond
digits patched in per line. A generation counter bumped by
`set_turn_log_timestamp_format()` invalidates live caches on a format
change; a format rendering longer than the cache falls back to the
caller's buffer.

Timestamp rendering, 12 threads on a 12-core machine:

| threads | before (no ms) | after (with ms) |
|---|---:|---:|
| 1 | 163 ns/line | 24 ns/line |
| 4 | 53 ns/line | 6 ns/line |
| 12 | **304 ns/line** | **3 ns/line** |

## Acceptance check

Output run against the stock logstash pattern `%{TIMESTAMP_ISO8601:ts}
%{LOGLEVEL:level} %{GREEDYDATA:msg}` — **43/44 startup lines parse with
no further configuration**, fields extracting correctly.

The one failure is pre-existing: the banner at `mainrelay.c:3211` embeds
`\n\n` *inside* the message, so its text lands on a line with no prefix.
The right fix is newline normalisation in the logger, not patching call
sites; deferred to the `--log-format` work.

## Compatibility

This is a visible break for anyone parsing coturn logs.
`--new-log-timestamp=false` restores the old timestamp but not the
thread id or the colons — there is no single flag that restores the
previous line verbatim. Worth pairing with the remaining logging changes
in one release and one changelog entry.

## Testing

All re-run after the rebase onto `441d3e9c`.

**Linux (Docker)**
- `ctest` 17/17
- `run_tests.sh`, `run_tests_conf.sh`, `run_tests_mobile.sh`,
`run_tests_multiplex_peer.sh`, `run_tests_rfc5780.sh`,
`run_tests_stateless_nonce.sh`, `run_tests_dtls_default.sh` — all
`rc=0`, zero `FAIL` lines
- Both timestamp modes confirmed on glibc: `2026-08-03T00:46:59.742+0000
INFO ...` and, with `--new-log-timestamp=false`, `0 INFO ...`

**macOS**
- `ctest` 18/18; `run_tests.sh`, `run_tests_conf.sh`,
`run_tests_mobile.sh`, `run_tests_stateless_nonce.sh` — all `rc=0`, zero
`FAIL` lines
- `clang-format` clean

**Fuzzing smoke**
- `fuzzing/run-local.sh ASan 0 -runs=1` and `ASan 1 -runs=1` — both
clean, no new findings

**Format matrix**, by hand on both platforms — default,
`--new-log-timestamp=false`, explicit on, and the same three through the
**config-file** path (a separate parser, also changed).

**Timestamp-cache correctness** — milliseconds vary per line (51
distinct timestamps across 7 seconds under traffic); format edge cases:
no `%f`, `%f` alone, `%f` at start, `%f` at end, `100%%f-%T.%f` (escaped
`%%f` stays literal while the real one expands), and a >128-byte format
hitting the fallback.

The MSVC branch of `turn_wall_clock()` (`GetSystemTimeAsFileTime`) is
inspection-only — there is no MSVC toolchain here, so CI is the first
real check on it.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 19:32:25 -07:00
..
2018-10-23 07:44:03 +02:00
2018-10-23 07:44:03 +02:00
2020-04-30 17:39:39 +03:00

Before you begin
 * copy db schema run ./cp-schema.sh
 * edit coturn/turnserver.conf according your db selection (mysql or postgresql or redis or mongodb)

# start

  docker-compose -f docker-compose-all.yml up --build --detach

# restart
Notice: May restart needed for coturn container, if it could not access database yet, due initialization delay.
  docker restart docker_coturn_1

# stop
  docker-compose -f docker-compose-all.yml down


# Or Stop with volume removal
  docker-compose down --volumes