You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在基于swift-argument-parser的异步命令行工具中初始化swift-log

解决方案:自定义根命令的main方法

直接在根命令结构体中实现static func main()方法,在解析命令行参数前完成日志系统的一次性初始化,这是最直接可靠的方式。

修改你的根命令代码如下:

import Foundation
import ArgumentParser
import Logging

@main struct Cfddns: AsyncParsableCommand {
    static let configuration = CommandConfiguration(
        subcommands: [SecretCommand.self],
        defaultSubcommand: SecretCommand.self)
    
    static func main() async {
        // 仅执行一次的全局初始化逻辑
        LoggingSystem.bootstrap { label in
            var handler = StreamLogHandler.standardOutput(label: label)
            handler.logLevel = .info
            // 在这里添加你的自定义日志配置(比如格式、元数据等)
            return handler
        }
        
        // 调用ArgumentParser默认的命令处理逻辑
        do {
            try await self.main()
        } catch {
            Self.exit(withError: error)
        }
    }
}

为什么这个方案可行?

  • 这个static func main()会替代ArgumentParser自动生成的程序入口,启动时只会执行一次,完全满足日志系统仅初始化一次的要求。
  • 无需修改任何子命令代码,也不用依赖单例或复杂条件判断,逻辑清晰且维护成本低。

之前方案失效的原因

  1. 根命令run()不执行:使用子命令时,ArgumentParser会直接路由到对应子命令的run(),根命令的run()不会被触发,因此无法在这里放初始化代码。
  2. init()多次执行:ArgumentParser在解析命令、生成帮助信息等场景中,会多次实例化命令结构体,导致init()被调用多次,即使加条件判断也可能因为并发或重复实例化多次执行。
  3. 子命令run()初始化:虽能生效,但需要在所有子命令的run()中添加判断,容易遗漏,维护风险高。

备选方案:全局惰性变量初始化

可以定义一个全局惰性变量,利用其仅初始化一次的特性完成日志配置:

import Logging

// 惰性变量仅在首次被访问时初始化
private let logInitializer: Void = {
    LoggingSystem.bootstrap { label in
        StreamLogHandler.standardOutput(label: label)
    }
}()

// 在子命令的run()中引用变量触发初始化
struct SecretCommand: AsyncParsableCommand {
    mutating func run() async throws {
        _ = logInitializer // 触发全局日志初始化
        // 后续业务逻辑...
    }
}

不过这个方案需要确保所有子命令都引用该变量,否则可能无法触发初始化,可靠性不如自定义main方法。

内容的提问来源于stack exchange,提问作者gwcoffey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 05:42:37