From 565e5fc9e626c482084cf2f5e1d09abe7a57ef31 Mon Sep 17 00:00:00 2001 From: Franz Busch Date: Thu, 8 Aug 2024 13:48:44 +0100 Subject: [PATCH] Introduce task local logger # Motivation Structured logging and structured concurrency are a match made in heaven. Using task locals for loggers enables easier passing of metadata for log messages and removes the cumbersome passing around of loggers. # Modification This PR adds a proposal, the implementation and benchmarks for a task local logger. # Result Using a task local for logging makes it incredible ergonomic to carry around metadata. To be transparent the benchmarks show that this is around 20x slower than a bare no-op log. A no-op log takes around 2ns whereas a task local logger no-op log takes around 40ns. 95% of that time is spent in accessing the task local since that is missing some `@inlinable` in the runtime and goes through the C interface. Instruction wise it is 20 vs 290 instructions. Now I still propose that we go forward with this since the ergonomics far outweigh the performance initially. Furthermore, this acts as a great forcing function for performance improvements in the runtime since logging is often done in hot paths. --- Benchmarks/.gitignore | 9 ++ .../LoggingBenchmarks/Benchmarks.swift | 58 +++++++++ Benchmarks/Package.swift | 27 +++++ Sources/Logging/Logging.swift | 8 +- Tests/LoggingTests/TaskLocalLoggerTests.swift | 32 +++++ proposals/0002-task-local-logger.md | 114 ++++++++++++++++++ 6 files changed, 246 insertions(+), 2 deletions(-) create mode 100644 Benchmarks/.gitignore create mode 100644 Benchmarks/Benchmarks/LoggingBenchmarks/Benchmarks.swift create mode 100644 Benchmarks/Package.swift create mode 100644 Tests/LoggingTests/TaskLocalLoggerTests.swift create mode 100644 proposals/0002-task-local-logger.md diff --git a/Benchmarks/.gitignore b/Benchmarks/.gitignore new file mode 100644 index 00000000..2517bcdf --- /dev/null +++ b/Benchmarks/.gitignore @@ -0,0 +1,9 @@ +.DS_Store +/.build +/Packages +xcuserdata/ +DerivedData/ +.swiftpm/configuration/registries.json +.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +.netrc +.benchmarkBaselines/ \ No newline at end of file diff --git a/Benchmarks/Benchmarks/LoggingBenchmarks/Benchmarks.swift b/Benchmarks/Benchmarks/LoggingBenchmarks/Benchmarks.swift new file mode 100644 index 00000000..cd47cf9d --- /dev/null +++ b/Benchmarks/Benchmarks/LoggingBenchmarks/Benchmarks.swift @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift Logging API open source project +// +// Copyright (c) 2024 Apple Inc. and the Swift Logging API project authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift Logging API project authors +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// + +import Benchmark +import Logging + +let benchmarks = { + let defaultMetrics: [BenchmarkMetric] = [ + .mallocCountTotal, + .instructions, + .wallClock, + ] + + Benchmark( + "NoOpLogger", + configuration: Benchmark.Configuration( + metrics: defaultMetrics, + scalingFactor: .mega, + maxDuration: .seconds(10_000_000), + maxIterations: 100 + ) + ) { benchmark in + let logger = Logger(label: "Logger", SwiftLogNoOpLogHandler()) + + for _ in 0..