如何在swift中打印出方法名称和行号

os8fio9y  于 2022-11-21  发布在  Swift
关注(0)|答案(6)|浏览(114)

下面是我想做的一个例子:

func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError)
{
    let  nm =  NetworkModel()
    nm.sendlog("file name :AppDelegate , line number : 288", info: " Failed to register: \(error)")
}

当前场景I完成了硬编码值line numberfile name,但是有可能通过程序挑选line numberfile name吗?

jdgnovmf

jdgnovmf1#

Literal        Type     Value

#file          String   The name of the file in which it appears.
#line          Int      The line number on which it appears.
#column        Int      The column number in which it begins.
#function      String   The name of the declaration in which it appears.
#dsohandle     UnsafeMutablePointer   The dso handle.

示例

print("Function: \(#function), line: \(#line)")

使用参数中的默认值,还可以创建函数

public func track(_ message: String, file: String = #file, function: String = #function, line: Int = #line ) { 
    print("\(message) called from \(function) \(file):\(line)") 
}
  • 可以像这样使用 *
track("enters app")

在Swift 2.1中

Literal        Type     Value

__FILE__       String   The name of the file in which it appears.
__LINE__       Int      The line number on which it appears.
__COLUMN__     Int      The column number in which it begins.
__FUNCTION__   String   The name of the declaration in which it appears.

有关详细信息,请参阅文档

qlfbtfca

qlfbtfca2#

您可以使用#function#file#line
下面是swift中log方法的实现:https://github.com/InderKumarRathore/SwiftLog
下面是代码片段

public func debugLog(object: Any, functionName: String = #function, fileName: String = #file, lineNumber: Int = #line) {
  #if DEBUG
    let className = (fileName as NSString).lastPathComponent
    print("<\(className)> \(functionName) [#\(lineNumber)]| \(object)\n")
  #endif
}
daolsyd0

daolsyd03#

对于斯威夫特4斯威夫特5

func printLog(_ message: String, file: String = #file, function: String = #function, line: Int = #line) {
    #if DEVELOPMENT
        let className = file.components(separatedBy: "/").last
        print(" ❌ Error ----> File: \(className ?? ""), Function: \(function), Line: \(line), Message: \(message)")
    #endif
}

// "❌ Error ----> File: classNameViewController.swift, function: functionName(), Line: 123, Message: messageError"
cnh2zyt3

cnh2zyt34#

示例日志代码(TL; DR)的

import os.log

@available(OSX 11.0, iOS 14.0, *)
extension Logger {
  private static var subsystem = Bundle.main.bundleIdentifier!

  /// Logs the payment flows like Apple Pay.
  @available(OSX 11.0, iOS 14.0, *)
  static let payments = Logger(subsystem: subsystem, category: "payments")
}

static func DLog(message: StaticString, file: StaticString = #file, function: StaticString = #function, line: UInt = #line, column: UInt = #column, category: String, type: OSLogType = .info, bundle: Bundle = .main) {

  // This method is only for iOS 14+
  if #available(OSX 11.0, iOS 14.0, *) {

    Logger.payments.debug("\(file) : \(function) : \(line) : \(column) - \(message, privacy: .private)")
    // This makes the message unreadable without a debugger attached.

  } else {
    // Fallback on earlier versions

    let customLog = OSLog(subsystem: bundle.bundleIdentifier!,
                          category: category)

    // IMPORTANT: I have assumed here that you only print out non-sensitive data! Using %{private}@ or %{public}@ in an interpolated string is not portable to `Logger`!
    os_log(message, log: customLog, type: type)

    // Unfortunately this legacy API doesn't support non-StaticString logs. :(
  }
}

请注意,您可能需要重新编写此代码,以便在私有/公共访问级别上获得更大的灵活性-os_logLogger处理隐私级别的方式不同。这只是为了说明如果您没有在message中添加os_log隐私级别,如何使用API。
Apple建议使用OS Logging,这也是我使用这种方法而不是print语句的原因。我添加这个答案是因为iOS 14中新的Logger API也支持字符串插值。

动机

我认为这里的答案解决了**〈iOS 14的问题,但它们可以进一步提高内存效率**,因为这个调试日志记录功能可能会在iOS 14+(新的Logger API)的所有代码库中使用。苹果建议使用操作系统日志记录,这就是为什么我使用这种方法而不是print语句(尽管这些语句仍然有效)。
这些都是 * 微小 * 的改进,但我认为它们能有所帮助,因为即使是微小的改进也会累积起来。事实上,Swift标准库在任何地方都使用了这些优化)!这些优化是Swift难以置信的内存效率的贡献因素,尽管Swift是一种高级语言(也是伟大API设计的一部分!)。(-:
因为这个函数很可能适合作为一个通用的(OS)日志服务的一部分,所以我还包括了
注意事项我在应用程序内进行日志记录时所做的。我认为这些可以帮助你调试日志**(我回答这个问题是因为它可能是调试日志!)

改进

1.如果我知道Int将是,并且不太可能发生任何边缘情况崩溃,我更喜欢在某些情况下使用UInt。由于这个原因,我在与使用Int类型的Foundation类接口时使用UInt。这分配的内存较少而且我发现更具体也能帮助我更好地理解代码。
1.我更喜欢使用StaticString,因为我知道字符串在编译时是已知的。StaticString仅提供对String内容的低级访问,并且是不可变的。因此,请仅在适当的地方使用它。即使是串联的字符串文本也不能用于初始化StaticString。因为它的功能比String受到更多限制,这意味着它是轻量级-仅需要一个地址指针和长度。使用StaticString还通过操作系统级内存管理提供少量性能提升,因为它既不分配也不释放(需要引用计数)。
1.使用Apple推荐的Logger API进行日志记录优于打印语句,原因如下:性能、隐私和统一管理。它可以更好地调试已发布产品中的问题(操作系统日志提供更多上下文)。
我建议你尽可能使用StaticString,比如函数名和文件名,行号和列号使用UInt。现在只有Logger iOS 14+ API才能做到这一点。

(额外)记录注意事项

我是否应该进行大量日志记录?

我认为日志记录是一个平衡的行为。如果你有权限访问崩溃报告,大量的日志记录对调试问题非常有帮助。但是,你需要平衡隐私,编译的二进制文件的大小和压倒日志记录系统。

1.隐私:"\(message, privacy: .private)""\(message, privacy: .public)"Logger一起使用时,请对敏感信息进行密文处理,并且在使用NSLogprint语句时,请勿打印敏感信息。建议在用于调试目的时,将print语句(用于生产)替换为操作系统日志。或者在日志记录服务中使用预处理器指令(#if DEBUG),以便仅在Debug方案上使用print
2.编译后的二进制文件的大小:日志语句实际上是更多行代码。添加的代码越多,二进制文件就越大。这通常不是问题,只要你不记录所有的东西,因为只有大幅增加此指标才会影响二进制文件的大小
3.日志系统不堪重负:如果你过多地记录日志,设备可能不得不丢弃一些日志以保持运行(由于操作系统的多任务处理,运行时的RAM或交换空间有限--对于旧设备来说更糟糕)。苹果通常在处理大量用户日志方面是可靠的,但在实践中很难做到。然而,如果你确实遇到了这种情况,一些更有用的日志事件可能会被推出窗口。

操作系统日志

最重要的是日志级别。默认情况下,在iOS上,日志级别为.info及以下的日志条目将在日志生成时被抑制,因此唯一真实的的负面影响是二进制大小。如果您.log进行日志记录(.default for os_log)或更高,您需要小心不要记录太多。Apple的一般建议是,您查看每个更高级别的日志条目,以确保它们包含在调试时可能有用的信息。
最后,确保设置子系统和类别。统一日志记录系统处理大量日志条目-带类别的子系统使您更容易关注特定问题

如何选择类别和子系统?

这是一个相当固执己见的主题,所以我会把重点放在我在做决定时会想到什么上。YMMV:可能有更好的选择,如果有,请让我知道。

**1.按功能(特定于产品):**例如,如果你是一个购物应用,可以按paymentlogin或其他应用流程来组织subsystem。如果你还没有使用模块化代码库来组织功能(或共享代码的框架),那么我可以推荐this tutorial series
**2.通过技术:**我的意思是代码的领域,它是用于推送通知、深度链接、用户默认值(或持久性)逻辑吗?这可能对category参数有帮助。
**3.按目标:**如果可以的话,我也喜欢使用当前BundlebundleIdentifier。如果您有扩展目标(推送通知)、多个目标或不同的平台(如WatchOS、SiriKit扩展等),这会更有意义。您可以使用以下代码获得当前捆绑包:

let myBundle = Bundle(for: MyClass.self)

使用操作系统设备日志调试用户问题

请参阅here以获得详细的演练(Access Device Console Logs)。主要思想是将设备连接到您的Mac(或者使用Mac本身来运行Mac应用程序;)),打开Console.app,运行应用程序并尝试重现崩溃。如果你一开始就设法做到了这一点,那么你可以将崩溃时间与日志相关联,以获得更多的上下文。

还有其他减少伐木的原因吗?

如果你是一个苹果早期采用者,那么你知道如何错误的一些iOS测试可以;)。向Apple发布错误报告时,操作系统日志会包含在sysdiagnose文件中,因此您可以获得更快的周转时间,因为您的错误报告噪音更小

我是否应该使用第三方日志记录服务?

取决于您是否负担得起以及是否真的需要。我倾向于最小化我在代码中导入的第三方依赖项的数量(如果我能控制这一点的话)而本机(Apple)Logging API在我的大多数用例中运行良好,但优点是用户无法查看日志(即使他想这样做)。请注意,如果您应用**.private日志级别,所以我通常不使用第三方服务(YMMV)。使用网络日志的一个潜在原因是,只要您信任第三方供应商防止数据泄露,它可以更安全地防止逆向工程**(但它不太环保;)).

niwlg2el

niwlg2el5#

static func DLog(message: String, file: String = #file, function: String = #function, line: Int = #line, column: Int = #column) {
    print("\(file) : \(function) : \(line) : \(column) - \(message)")
}
yftpprvb

yftpprvb6#

在代码中的任意位置(在struct/var/closure/func...中)添加下一行:

let _ = print("**** \(#file)" + String(describing: type(of: self)) + ".\(#function)[\(#line)]")

它将打印下一行:

**** /path/to/my/file.swift MyClass.someFunc()[17]

相关问题