Skip to content

Commit

Permalink
added print stack trace
Browse files Browse the repository at this point in the history
  • Loading branch information
kibotu committed Jul 1, 2024
1 parent 8c0ec88 commit 189e0d0
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 0 deletions.
70 changes: 70 additions & 0 deletions Sources/Orchard/Extensions/Thread+Extensions.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import Foundation

public extension Thread {
static var callStack: [String] {
Thread
.callStackSymbols // drop Thread.callStack
.dropFirst()
.map { line in
let parts = line.split(separator: " ")
let index = parts[0]
let module = parts[1]
let method = demangle("\(parts[3])")
return "[\(module)] \(method)"
}
}

static func printStackTrace() {
callStack
.dropFirst() // drop Thread.printStacktrace
.forEach { line in
Orchard.d("[\(Thread.betterIdentifier)]\(line)")
}
}

static var betterIdentifier: String {
if isMainThread {
return "Main"
} else {
// Attempt to get a thread number by parsing the description since there's no public API for it.
// Note: This is not guaranteed to work in all future versions of Swift.
let description = Thread.current.description
let regex = try! NSRegularExpression(pattern: "number = (\\d+)", options: [])
let nsrange = NSRange(description.startIndex..<description.endIndex, in: description)

if let match = regex.firstMatch(in: description, options: [], range: nsrange),
let range = Range(match.range(at: 1), in: description) {
let number = String(description[range])
return "Thread-\(number)"
} else {
// As a fallback, use the memory address of the Thread object.
return "Thread-<\(Unmanaged.passUnretained(Thread.current).toOpaque())>"
}
}
}
}

public typealias SwiftDemangle = @convention(c) (_ mangledName: UnsafePointer<CChar>?, _ mangledNameLength: Int, _ outputBuffer: UnsafeMutablePointer<CChar>?, _ outputBufferSize: UnsafeMutablePointer<Int>?, _ flags: UInt32) -> UnsafeMutablePointer<CChar>?

public let RTLD_DEFAULT = dlopen(nil, RTLD_NOW)
public let demangleSymbol = dlsym(RTLD_DEFAULT, "swift_demangle")!
public let cDemangle = unsafeBitCast(demangleSymbol, to: SwiftDemangle.self)

public func demangle(_ mangled: String) -> String {
mangled.withCString { cString in
// Prepare output buffer size
var size: Int = 0
let ptr = cDemangle(cString, strlen(cString), nil, &size, 0)

// Check if demangling was successful
guard let result = ptr else { return mangled }

// Convert demangled name to string
let demangledName = String(cString: result)

// Free memory allocated by swift_demangle (if necessary)
free(result)

return demangledName
}
}
10 changes: 10 additions & 0 deletions Sources/Orchard/Orchard.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import Foundation

/// Orchard: A versatile and unified logging system for Swift applications
///
/// The `Orchard` class provides a centralized logging mechanism that allows for easy integration
Expand Down Expand Up @@ -184,6 +186,14 @@ public class Orchard {
public static func < (lhs: Level, rhs: Level) -> Bool {
lhs.severityOrder < rhs.severityOrder
}

public static func printStackTrace() {
Thread.printStackTrace()
}

public static var callStack: [String] {
return Thread.callStack
}
}

/// Protocol defining the interface for custom loggers
Expand Down

0 comments on commit 189e0d0

Please sign in to comment.