Document version 3.0.0 changes and migration
This commit is contained in:
1 parent
5a2418f438
commit
9fa158f68d
2 files changed
+96
-4
No files matched your search
@@ -0,0 +1,89 @@
|
||||
# Changelog
|
||||
|
||||
## 3.0.0
|
||||
|
||||
This release reworks logging ownership for Nim's ORC memory manager, fixes
|
||||
background writer shutdown, and switches generated timestamps to UTC. It
|
||||
introduces breaking API changes from 2.1.2. Nim 2.2.0 or later remains required.
|
||||
|
||||
### Breaking changes and migration
|
||||
|
||||
- **Service handles and local caches are separate types.** `LogService` is now
|
||||
a copyable handle that keeps shared configuration alive. Pass a copy to each
|
||||
worker, then call `threadLocalRef()` inside that worker. Keep
|
||||
`ThreadLocalLogService` and its loggers in the thread that creates them. Use
|
||||
`local.service` instead of `local[]` to obtain a shared handle.
|
||||
- **`ensureFreshness(LogService)` has been removed.** Refresh the relevant
|
||||
`ThreadLocalLogService` instead. Configuration methods remain available on
|
||||
both types; `LogService.appenders()` returns clones of the current shared
|
||||
configuration.
|
||||
- **Custom appender callbacks now receive `state: var T`.**
|
||||
`initCustomLogAppender` copies supported value state into each clone and
|
||||
rejects ordinary references, closures, and embedded synchronization
|
||||
primitives, including nested ones. Use `SharedLogState[T]` for shared mutable
|
||||
value data, or `initFactoryCustomLogAppender` for independently created state
|
||||
containing references or closures.
|
||||
- **Appenders now accept `LogFormatter` objects.** The former
|
||||
`LogMessageFormatter` callback type is replaced by `StatefulLogFormatterFunc`
|
||||
and `StatelessLogFormatterFunc`. Noncapturing formatter functions still
|
||||
convert automatically. Replace directly supplied captured closures with
|
||||
`initLogFormatter(seed, factory)`, and use `formatter.format(message)` to
|
||||
invoke a formatter directly. Custom appender and formatter clones must own
|
||||
independent state or use explicit shared-state handles.
|
||||
- **Generated timestamps now use UTC.** `LogMessage.ts` remains a `DateTime`;
|
||||
structured JSON output uses a `Z` suffix. Explicit timestamps supplied in
|
||||
caller-constructed messages are preserved.
|
||||
- **The test collector returns value snapshots.** `LoggedMessages.get()` now
|
||||
returns `seq[RecordedLogMessage]` instead of `seq[LogMessage]`. Timestamps are
|
||||
`Time` values, additional JSON data is serialized text, and exceptions retain
|
||||
their name, message, and stacktrace as text. Use the collector's methods
|
||||
instead of accessing its former `messages` field.
|
||||
|
||||
### Added
|
||||
|
||||
- `SharedLogState[T]` and `initSharedLogState` provide copyable ownership of
|
||||
shared value data. Use `withState` for synchronized updates and `snapshot`
|
||||
for independent copies. Raw pointers and custom copy/destruction hooks
|
||||
remain the caller's responsibility.
|
||||
- `FactoryCustomLogAppender` and `initFactoryCustomLogAppender` create custom
|
||||
state lazily within the thread using each clone. Formatter factories provide
|
||||
the same ownership pattern for captured formatter state. Configuration
|
||||
refresh can replace clones and reset their local state; use shared-state
|
||||
handles for data that must persist across refreshes.
|
||||
|
||||
### Fixed and clarified
|
||||
|
||||
- Service copies retain shared configuration without sharing ordinary ORC
|
||||
reference ownership between threads. Workers can outlive the original
|
||||
handle and the thread that created it.
|
||||
- Local caches are built independently. Failed configuration refreshes preserve
|
||||
the previous cache and retry on a later refresh without requiring another
|
||||
configuration change.
|
||||
- Background console and file writers drain queued records at normal process
|
||||
exit, including empty messages and the final file batch. Shutdown excludes
|
||||
further submissions and waits for writers to finish. Applications must join
|
||||
their logging workers before exiting.
|
||||
- Both message constructors avoid local-time conversion races by creating UTC
|
||||
timestamps directly.
|
||||
- `isEnabled` intentionally checks cached namespace thresholds without
|
||||
refreshing configuration. Logging calls, `getLogger`, or an explicit local
|
||||
refresh pick up changes. Applications that guard all logging should refresh
|
||||
at suitable boundaries, such as the start of a request. The shared root
|
||||
threshold is read only when no cached namespace threshold applies.
|
||||
|
||||
### Tests and known limitations
|
||||
|
||||
- `nimble test` runs all enabled unit, regression, and ThreadSanitizer suites
|
||||
under ORC with threads enabled. Individual suites remain available through
|
||||
`testUnit`, `testRegression`, and `testThreadSafety`.
|
||||
- Validation passes 32 unit tests, 29 regression tests, and 11 sanitizer
|
||||
scenarios. Two scenarios, `factory-state` and `allocator`, are temporarily
|
||||
skipped because they expose a known race in Nim 2.2.10's default allocator.
|
||||
Their code and assertions remain available; enable them with
|
||||
`NSL_TEST_RUNTIME_ALLOCATOR=1 nimble testThreadSafety`.
|
||||
- The allocator limitation remains unresolved and also reproduces without
|
||||
importing this library. Passing the enabled tests does not establish full
|
||||
validation of factory state under the default allocator. See
|
||||
[the test documentation](tests/README.md) for details and diagnostic results.
|
||||
|
||||
See the [README](README.md) for usage and migration examples.
|
||||
Reference in new issue
Block a user