diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c996440a4..0e3822e96 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,9 +27,9 @@ concurrency: jobs: test-linux: name: Test - runs-on: ubuntu-latest + runs-on: ubuntu-24.04-arm container: - image: registry.gitlab.com/finestructure/spi-base:1.1.1 + image: registry.gitlab.com/finestructure/spi-base:1.1.1-arm options: --privileged services: postgres: @@ -64,7 +64,7 @@ jobs: name: Release build runs-on: ubuntu-latest container: - image: registry.gitlab.com/finestructure/spi-base:1.1.1 + image: registry.gitlab.com/finestructure/spi-base:1.1.1-arm options: --privileged steps: - name: GH Runner bug workaround diff --git a/Makefile b/Makefile index af61190a3..fda097e6b 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ run: test: xcbeautify set -o pipefail \ - && swift test --disable-automatic-resolution --sanitize=thread --no-parallel \ + && swift test --disable-automatic-resolution --no-parallel \ 2>&1 | ./xcbeautify --renderer github-actions test-query-performance: xcbeautify diff --git a/Sources/App/Commands/Alerting.swift b/Sources/App/Commands/Alerting.swift index e9633322b..65a9e97dd 100644 --- a/Sources/App/Commands/Alerting.swift +++ b/Sources/App/Commands/Alerting.swift @@ -42,8 +42,10 @@ enum Alerting { } func run(using context: CommandContext, signature: Signature) async throws { + prepareDependencies { + $0.logger = Logger(component: "alerting") + } @Dependency(\.logger) var logger - logger.set(to: Logger(component: "alerting")) logger.info("Running alerting...") diff --git a/Sources/App/Commands/Analyze.swift b/Sources/App/Commands/Analyze.swift index 39b449954..990e6f765 100644 --- a/Sources/App/Commands/Analyze.swift +++ b/Sources/App/Commands/Analyze.swift @@ -28,10 +28,13 @@ enum Analyze { var help: String { "Run package analysis (fetching git repository and inspecting content)" } func run(using context: CommandContext, signature: SPICommand.Signature) async throws { + prepareDependencies { + $0.logger = Logger(component: "analyze") + } + @Dependency(\.logger) var logger + let client = context.application.client let db = context.application.db - @Dependency(\.logger) var logger - logger.set(to: Logger(component: "analyze")) Analyze.resetMetrics() @@ -251,7 +254,7 @@ extension Analyze { attributes: nil) } catch { let error = AppError.genericError(nil, "Failed to create checkouts directory: \(error.localizedDescription)") - logger.logger.report(error: error) + logger.report(error: error) } } diff --git a/Sources/App/Commands/Ingestion.swift b/Sources/App/Commands/Ingestion.swift index 47e8996a4..fddf6cf97 100644 --- a/Sources/App/Commands/Ingestion.swift +++ b/Sources/App/Commands/Ingestion.swift @@ -82,10 +82,13 @@ enum Ingestion { var help: String { "Run package ingestion (fetching repository metadata)" } func run(using context: CommandContext, signature: SPICommand.Signature) async { + prepareDependencies { + $0.logger = Logger(component: "ingest") + } + @Dependency(\.logger) var logger + let client = context.application.client let db = context.application.db - @Dependency(\.logger) var logger - logger.set(to: Logger(component: "ingest")) Self.resetMetrics() diff --git a/Sources/App/Commands/ReAnalyzeVersions.swift b/Sources/App/Commands/ReAnalyzeVersions.swift index 5741908cf..d7b4543f5 100644 --- a/Sources/App/Commands/ReAnalyzeVersions.swift +++ b/Sources/App/Commands/ReAnalyzeVersions.swift @@ -43,12 +43,15 @@ enum ReAnalyzeVersions { var help: String { "Run version re-analysis" } func run(using context: CommandContext, signature: Signature) async throws { + prepareDependencies { + $0.logger = Logger(component: "re-analyze-versions") + } + @Dependency(\.logger) var logger + let limit = signature.limit ?? defaultLimit let client = context.application.client let db = context.application.db - @Dependency(\.logger) var logger - logger.set(to: Logger(component: "re-analyze-versions")) @Dependency(\.date.now) var now if let id = signature.packageId { diff --git a/Sources/App/Commands/Reconcile.swift b/Sources/App/Commands/Reconcile.swift index 90f31195b..14c9aa647 100644 --- a/Sources/App/Commands/Reconcile.swift +++ b/Sources/App/Commands/Reconcile.swift @@ -23,14 +23,15 @@ struct ReconcileCommand: AsyncCommand { var help: String { "Reconcile package list with server" } func run(using context: CommandContext, signature: Signature) async throws { + prepareDependencies{ + $0.logger = Logger(component: "reconcile") + } @Dependency(\.logger) var logger - logger.set(to: Logger(component: "reconcile")) logger.info("Reconciling...") do { - try await reconcile(client: context.application.client, - database: context.application.db) + try await reconcile(client: context.application.client, database: context.application.db) } catch { logger.error("\(error)") } @@ -38,8 +39,7 @@ struct ReconcileCommand: AsyncCommand { logger.info("done.") do { - try await AppMetrics.push(client: context.application.client, - jobName: "reconcile") + try await AppMetrics.push(client: context.application.client, jobName: "reconcile") } catch { logger.warning("\(error)") } diff --git a/Sources/App/Commands/TriggerBuilds.swift b/Sources/App/Commands/TriggerBuilds.swift index 2fc9ce4aa..352bb54b1 100644 --- a/Sources/App/Commands/TriggerBuilds.swift +++ b/Sources/App/Commands/TriggerBuilds.swift @@ -55,8 +55,10 @@ struct TriggerBuildsCommand: AsyncCommand { } func run(using context: CommandContext, signature: Signature) async throws { + prepareDependencies { + $0.logger = Logger(component: "trigger-builds") + } @Dependency(\.logger) var logger - logger.set(to: Logger(component: "trigger-builds")) Self.resetMetrics() diff --git a/Sources/App/Core/Dependencies/LoggerClient.swift b/Sources/App/Core/Dependencies/LoggerClient.swift index b5cd45b59..257878bfd 100644 --- a/Sources/App/Core/Dependencies/LoggerClient.swift +++ b/Sources/App/Core/Dependencies/LoggerClient.swift @@ -13,55 +13,20 @@ // limitations under the License. import Dependencies -import DependenciesMacros +import IssueReporting import Logging -import Synchronization -@DependencyClient -struct LoggerClient { - var log: @Sendable (_ level: Logging.Logger.Level, Logging.Logger.Message) -> Void - var set: @Sendable (_ to: Logging.Logger) -> Void -} - - -extension LoggerClient { - func critical(_ message: Logging.Logger.Message) { log(.critical, message) } - func debug(_ message: Logging.Logger.Message) { log(.debug, message) } - func error(_ message: Logging.Logger.Message) { log(.error, message) } - func info(_ message: Logging.Logger.Message) { log(.info, message) } - func warning(_ message: Logging.Logger.Message) { log(.warning, message) } - func trace(_ message: Logging.Logger.Message) { log(.trace, message) } - func report(error: Error, file: String = #fileID, function: String = #function, line: UInt = #line) { - logger.report(error: error, file: file, function: function, line: line) +private enum LoggerClient: DependencyKey { + static var liveValue: Logger { + reportIssue("The default logger is being used. Override this dependency in the entry point of your app.") + return Logging.Logger(label: "default") } - var logger: Logging.Logger { Self._logger.withLock { $0 } } -} - - -extension LoggerClient: DependencyKey { - static var liveValue: Self { - .init( - log: { level, message in - _logger.withLock { $0.log(level: level, message) } - }, - set: { logger in - _logger.withLock { $0 = logger } - } - ) - } - - private static let _logger = Mutex(Logging.Logger(component: "default")) -} - - -extension LoggerClient: TestDependencyKey { - static var testValue: Self { liveValue } } extension DependencyValues { - var logger: LoggerClient { + public var logger: Logger { get { self[LoggerClient.self] } set { self[LoggerClient.self] = newValue } } diff --git a/Sources/App/Core/Dependencies/ShellClient.swift b/Sources/App/Core/Dependencies/ShellClient.swift index 4efa5a510..7556be544 100644 --- a/Sources/App/Core/Dependencies/ShellClient.swift +++ b/Sources/App/Core/Dependencies/ShellClient.swift @@ -42,7 +42,7 @@ extension ShellClient: DependencyKey { run: { command, path in @Dependency(\.logger) var logger do { - let res = try await ShellOut.shellOut(to: command, at: path, logger: logger.logger) + let res = try await ShellOut.shellOut(to: command, at: path, logger: logger) if !res.stderr.isEmpty { logger.warning("stderr: \(res.stderr)") } diff --git a/Sources/App/configure.swift b/Sources/App/configure.swift index 25798673b..eaf90bd92 100644 --- a/Sources/App/configure.swift +++ b/Sources/App/configure.swift @@ -27,9 +27,7 @@ public func configure(_ app: Application) async throws -> String { let _ = Bundle(path: "/Applications/InjectionIII.app/Contents/Resources/macOSInjection.bundle")?.load() #endif - @Dependency(\.logger) var logger app.logger.component = "server" - logger.set(to: app.logger) // It will be tempting to uncomment/re-add these lines in the future. We should not enable // server-side compression as long as we pass requests through Cloudflare, which compresses diff --git a/Sources/Run/entrypoint.swift b/Sources/Run/entrypoint.swift index a8c2dfb75..cf7c3f857 100644 --- a/Sources/Run/entrypoint.swift +++ b/Sources/Run/entrypoint.swift @@ -13,9 +13,11 @@ // limitations under the License. import App +import Dependencies import Logging import Vapor + @main enum Entrypoint { static func main() async throws { @@ -24,6 +26,10 @@ enum Entrypoint { let app = try await Application.make(env) + prepareDependencies { + $0.logger = app.logger + } + do { try await configure(app) } catch { diff --git a/Tests/AppTests/AppTestCase.swift b/Tests/AppTests/AppTestCase.swift index 5d61b3b4f..5ff079505 100644 --- a/Tests/AppTests/AppTestCase.swift +++ b/Tests/AppTests/AppTestCase.swift @@ -29,8 +29,9 @@ class AppTestCase: XCTestCase { try await super.setUp() app = try await setup(.testing) - @Dependency(\.logger) var logger - logger.set(to: .init(label: "test", factory: { _ in self.logger })) + prepareDependencies { + $0.logger = .init(label: "test", factory: { _ in self.logger }) + } } func setup(_ environment: Environment) async throws -> Application { @@ -60,7 +61,7 @@ extension AppTestCase { try await configure(app) // Silence app logging - app.logger = .init(label: "noop") { _ in SwiftLogNoOpLogHandler() } + app.logger = .noop return app } @@ -205,3 +206,7 @@ private func withDatabase(_ databaseName: String, _ environment: Environment, _ } } + +extension Logger { + static var noop: Self { .init(label: "noop") { _ in SwiftLogNoOpLogHandler() } } +} diff --git a/Tests/AppTests/GitLiveTests.swift b/Tests/AppTests/GitLiveTests.swift index abe776a0d..6801364a3 100644 --- a/Tests/AppTests/GitLiveTests.swift +++ b/Tests/AppTests/GitLiveTests.swift @@ -43,8 +43,10 @@ class GitLiveTests: XCTestCase { } override func invokeTest() { + prepareDependencies { + $0.logger = .noop + } withDependencies { - $0.logger.log = { @Sendable _, _ in } $0.shell = .liveValue } operation: { super.invokeTest() diff --git a/Tests/AppTests/Helpers/TestSupport.swift b/Tests/AppTests/Helpers/TestSupport.swift index cd017f8d0..d2d47eaaf 100644 --- a/Tests/AppTests/Helpers/TestSupport.swift +++ b/Tests/AppTests/Helpers/TestSupport.swift @@ -29,11 +29,11 @@ func withApp(_ setup: (Application) async throws -> Void = { _ in }, return try await run { try await setup(app) try await withDependencies(updateValuesForOperation) { - let logger = logHandler.map { handler in Logger(label: "test", factory: { _ in handler }) } + let logger = logHandler + .map { handler in Logger(label: "test", factory: { _ in handler }) } + ?? Logging.Logger(label: "test") try await withDependencies { - if let logger { - $0.logger.set(to: logger) - } + $0.logger = logger } operation: { try await test(app) }