Skip to content

Update CPU, Architecture and OSInfo system attributes #154

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jun 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 32 additions & 6 deletions Sources/Features/Attributes/DefaultAttributes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,30 @@ struct Device: AttributesSource {
#endif
}

var immutable: [String: Any?] {
return [
"device.machine": try? System.machine(),
"device.model": try? System.machine(),
"uname.sysname": getSysname()
]
var immutable: [String : Any?] {
var result: [String : Any?] = [:]

let architecture = CPU.architecture()
result["device.arch"] = architecture
result["cpu.arch"] = architecture

let sysname = OSInfo.name
result["uname.sysname"] = sysname

let machine = try? System.machine()
result["uname.machine"] = machine
result["device.machine"] = machine

let model = try? System.model()
result["device.model"] = model

result["device.isSimulator"] = isSimulator()

result["device.osName"] = OSInfo.name
result["device.osVersion"] = OSInfo.version
result["device.osBuildNumber"] = OSInfo.buildNumber

return result
}

private func getSysname() -> String {
Expand All @@ -120,6 +138,14 @@ struct Device: AttributesSource {
return "Unsupported device"
#endif
}

func isSimulator() -> Bool {
#if targetEnvironment(simulator)
return true
#else
return false
#endif
}
}

struct ScreenInfo: AttributesSource {
Expand Down
143 changes: 131 additions & 12 deletions Sources/Features/Attributes/System.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import Foundation
import MachO
import Darwin

struct Statistics {

Expand Down Expand Up @@ -110,21 +112,39 @@ struct SystemControl {
return data
}

static func string(mib: [Int32]) throws -> String {
guard let string = try bytes(mib: mib).withUnsafeBufferPointer({ dataPointer -> String? in
dataPointer.baseAddress.flatMap { String(validatingUTF8: $0) }
}) else {
throw CodingError.encodingFailed
}
return string
}

static func value<T>(mib: [Int32]) throws -> T {
return try bytes(mib: mib).withUnsafeBufferPointer({ (buffer) throws -> T in
guard let baseAddress = buffer.baseAddress else { throw KernError.unexpected }
return baseAddress.withMemoryRebound(to: T.self, capacity: 1, { $0.pointee })
})
}

static func string(forKeys keys: [Int32]) throws -> String {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's the point of the string functioN?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we can change the function name it would be great.

var keys = keys
var size = 0
if sysctl(&keys, u_int(keys.count), nil, &size, nil, 0) != 0 {
throw SysctlError.sysctlFailed("Failed to get size of sysctl data.")
}

var data = [CChar](repeating: 0, count: size)
if sysctl(&keys, u_int(keys.count), &data, &size, nil, 0) != 0 {
throw SysctlError.sysctlFailed("Failed to get sysctl data.")
}

guard let result = String(cString: data, encoding: .utf8) else {
throw SysctlError.invalidUTF8("Failed to convert sysctl data to string.")
}
return result.trimmingCharacters(in: .whitespacesAndNewlines)
}

static func integer<T: FixedWidthInteger>(forName name: String) throws -> T {
var size = MemoryLayout<T>.stride
var value = T(0)
if sysctlbyname(name, &value, &size, nil, 0) != 0 {
throw SysctlError.sysctlFailed("Failed to read \(name).")
}
return value
}
}

struct MemoryInfo {
Expand Down Expand Up @@ -238,13 +258,112 @@ struct System {
}
return currentTime.tv_sec - bootTime
}

static func machine() throws -> String {
return try SystemControl.string(mib: [CTL_HW, HW_MACHINE])
return (try? SystemControl.string(forKeys: [CTL_HW, HW_MACHINE])) ?? "unknown"
}

static func model() throws -> String {
return try SystemControl.string(mib: [CTL_HW, HW_MODEL])
#if os(iOS) || os(tvOS) || os(watchOS)
return (try? SystemControl.string(forKeys: [CTL_HW, HW_MACHINE])) ?? "unknown"
#else
return (try? SystemControl.string(forKeys: [CTL_HW, HW_MODEL])) ?? "unknown"
#endif
}
}

struct CPU {
static func architecture() -> String {
do {
let cpuType: cpu_type_t = try SystemControl.integer(forName: "hw.cputype")
let cpuSubType: cpu_subtype_t = try SystemControl.integer(forName: "hw.cpusubtype")

return architectureString(cpuType: cpuType, cpuSubType: cpuSubType)
} catch {
return "unknown"
}
}

private static func architectureString(cpuType: cpu_type_t, cpuSubType: cpu_subtype_t) -> String {
switch cpuType {
case CPU_TYPE_X86:
switch cpuSubType {
case CPU_SUBTYPE_X86_64_H:
return "x86_64h"
case CPU_SUBTYPE_X86_64_ALL:
return "x86_64"
default:
return "x86"
}
case CPU_TYPE_X86_64:
return "x86_64"

case CPU_TYPE_ARM:
switch cpuSubType {
case CPU_SUBTYPE_ARM_V6:
return "armv6"
case CPU_SUBTYPE_ARM_V7:
return "armv7"
case CPU_SUBTYPE_ARM_V7S:
return "armv7s"
case CPU_SUBTYPE_ARM_V7K:
return "armv7k"
default:
return "arm"
}

case CPU_TYPE_ARM64, CPU_TYPE_ARM64_32:
switch cpuSubType {
case CPU_SUBTYPE_ARM64_V8:
return "armv8"
case CPU_SUBTYPE_ARM64E:
return "arm64e"
default:
return "arm64"
}

default:
return "unknown (type=\(cpuType), subType=\(cpuSubType))"
}
}
}

struct OSInfo {
static var name: String {
#if os(macOS)
return "macOS"
#elseif os(tvOS)
return "tvOS"
#elseif os(watchOS)
return "watchOS"
#elseif os(iOS) && !targetEnvironment(macCatalyst)
return UIDevice.current.systemName
#elseif os(iOS) && targetEnvironment(macCatalyst)
return "Catalyst"
#else
return "unknownOS"
#endif
}

static var version: String {
#if os(iOS) && !targetEnvironment(macCatalyst)
return UIDevice.current.systemVersion
#elseif os(watchOS)
let version = ProcessInfo.processInfo.operatingSystemVersion
return "\(version.majorVersion).\(version.minorVersion).\(version.patchVersion)"
#else
let version = ProcessInfo.processInfo.operatingSystemVersion
return "\(version.majorVersion).\(version.minorVersion).\(version.patchVersion)"
#endif
}

static var buildNumber: String {
let mib = [CTL_KERN, KERN_OSVERSION]
do {
return try SystemControl.string(forKeys: mib)
} catch {
return "unknown"
}
}
}

Expand Down
5 changes: 5 additions & 0 deletions Sources/Features/Error/BacktraceError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ enum CodingError: BacktraceError {
case encodingFailed
}

enum SysctlError: BacktraceError {
case sysctlFailed(String?)
case invalidUTF8(String?)
}

extension HttpError {
var backtraceStatus: BacktraceReportStatus {
switch self {
Expand Down