Skip to content
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
234 changes: 132 additions & 102 deletions Sources/TSCUtility/Tracing.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,127 +10,157 @@

import Foundation

public struct Tracing {
public enum EventType {
case asyncBegin
case asyncEnd
public enum TracingEventType {
case asyncBegin
case asyncEnd
}

public protocol TracingEventProtocol {
/// The category of the event.
var cat: String { get }

/// The name of the event.
var name: String { get }

/// The free form id of the event.
var id: String { get }

/// The phase of the event.
var ph: TracingEventType { get }

/// The process id of the process where the event occured.
var pid: Int { get }

/// The thread id of the process where the event occured.
var tid: Int { get }

/// The timestamp of the event.
var ts: Int { get }

/// The start time of the process where the event occured.
var startTs: Int { get }
init(
cat: String,
name: String,
id: String,
ph: TracingEventType,
pid: Int,
tid: Int,
ts: Int,
startTs: Int
)
}

public protocol TracingCollectionProtocol {
var events: [TracingEventProtocol] { get set }
init(_ events: [TracingEventProtocol])
}

extension TracingCollectionProtocol {
public mutating func append(_ tracingCollection: TracingCollectionProtocol) {
self.events.append(contentsOf: tracingCollection.events)
}
}

public struct Event {
/// The category of the event.
public let cat: String

/// The name of the event.
public let name: String

/// The free form id of the event.
public let id: String

/// The phase of the event.
public let ph: EventType

/// The process id of the process where the event occured.
public let pid: Int

/// The thread id of the process where the event occured.
public let tid: Int

/// The timestamp of the event.
public let ts: Int

/// The start time of the process where the event occured.
public let startTs: Int

#if canImport(Darwin)
public init(
cat: String,
name: String,
id: String,
ph: EventType,
pid: Int = Int(getpid()),
tid: Int = Int(pthread_mach_thread_np(pthread_self())),
ts: Int = Int(DispatchTime.now().uptimeNanoseconds),
startTs: Int = 0
) {
self.cat = cat
self.name = name
self.id = id
self.ph = ph
self.pid = pid
self.tid = tid
self.ts = ts
self.startTs = startTs
}
#elseif canImport(Glibc)
public init(
cat: String,
name: String,
id: String,
ph: EventType,
pid: Int = Int(getpid()),
tid: Int = 1,
ts: Int = Int(DispatchTime.now().uptimeNanoseconds),
startTs: Int = 0
) {
self.cat = cat
self.name = name
self.id = id
self.ph = ph
self.pid = pid
self.tid = tid
self.ts = ts
self.startTs = startTs
}
#else
public init(
cat: String,
name: String,
id: String,
ph: EventType,
pid: Int = 1,
tid: Int = 1,
ts: Int = Int(DispatchTime.now().uptimeNanoseconds),
startTs: Int = 0
) {
self.cat = cat
self.name = name
self.id = id
self.ph = ph
self.pid = pid
self.tid = tid
self.ts = ts
self.startTs = startTs
}
#endif
public struct TracingEvent: TracingEventProtocol {
public let cat: String
public let name: String
public let id: String
public let ph: TracingEventType
public let pid: Int
public let tid: Int
public let ts: Int
public let startTs: Int

#if canImport(Darwin)
public init(
cat: String,
name: String,
id: String,
ph: TracingEventType,
pid: Int = Int(getpid()),
tid: Int = Int(pthread_mach_thread_np(pthread_self())),
ts: Int = Int(DispatchTime.now().uptimeNanoseconds),
startTs: Int = 0
) {
self.cat = cat
self.name = name
self.id = id
self.ph = ph
self.pid = pid
self.tid = tid
self.ts = ts
self.startTs = startTs
}
#elseif canImport(Glibc)
public init(
cat: String,
name: String,
id: String,
ph: TracingEventType,
pid: Int = Int(getpid()),
tid: Int = 1,
ts: Int = Int(DispatchTime.now().uptimeNanoseconds),
startTs: Int = 0
) {
self.cat = cat
self.name = name
self.id = id
self.ph = ph
self.pid = pid
self.tid = tid
self.ts = ts
self.startTs = startTs
}
#else
public init(
cat: String,
name: String,
id: String,
ph: TracingEventType,
pid: Int = 1,
tid: Int = 1,
ts: Int = Int(DispatchTime.now().uptimeNanoseconds),
startTs: Int = 0
) {
self.cat = cat
self.name = name
self.id = id
self.ph = ph
self.pid = pid
self.tid = tid
self.ts = ts
self.startTs = startTs
}
#endif
}

public struct Collection {
public var events: [Event] = []
public init(_ events: [Tracing.Event] = []) {
self.events = events
}
public class TracingCollection: TracingCollectionProtocol {
public var events: [TracingEventProtocol] = []
public required init(_ events: [TracingEventProtocol] = []) {
self.events = events
}
}

extension Context {
public static func withTracing(_ collection: Tracing.Collection) -> Context {
return Context(dictionaryLiteral: (ObjectIdentifier(Tracing.Collection.self), collection as Any))
public static func withTracing(_ collection: TracingCollectionProtocol) -> Context {
return Context(dictionaryLiteral: (ObjectIdentifier(TracingCollectionProtocol.self), collection as Any))
}

public mutating func enrichWithTracing(_ collection: Tracing.Collection) -> Context {
self[ObjectIdentifier(Tracing.Collection.self)] = collection
public mutating func enrichWithTracing(_ collection: TracingCollectionProtocol) -> Context {
self[ObjectIdentifier(TracingCollectionProtocol.self)] = collection
return self
}

public var tracing: Tracing.Collection? {
public var tracing: TracingCollectionProtocol? {
get {
guard let collection = self[ObjectIdentifier(Tracing.Collection.self)] as? Tracing.Collection else {
guard let collection = self[ObjectIdentifier(TracingCollectionProtocol.self)] as? TracingCollectionProtocol else {
return nil
}
return collection
}
set {
self[ObjectIdentifier(Tracing.Collection.self)] = newValue
self[ObjectIdentifier(TracingCollectionProtocol.self)] = newValue
}
}
}
12 changes: 8 additions & 4 deletions Tests/TSCUtilityTests/TracingTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,19 @@ import TSCUtility

class TracingTests: XCTestCase {
func testBasics() {
let event1 = Tracing.Event(cat: "cat", name: "name", id: "1", ph: .asyncBegin)
var collection = Tracing.Collection()
let event1 = TracingEvent(cat: "cat", name: "name", id: "1", ph: .asyncBegin)
var collection = TracingCollection()
collection.events.append(event1)
let event2 = Tracing.Event(cat: "cat", name: "name", id: "1", ph: .asyncEnd)
let event2 = TracingEvent(cat: "cat", name: "name", id: "1", ph: .asyncEnd)
collection.events.append(event2)
XCTAssertEqual(collection.events.count, 2)
var ctx = Context()
ctx.tracing = collection
XCTAssertEqual(ctx.tracing?.events.count, 2)

let collection2 = TracingCollection()
collection2.events.append(event2)
collection.append(collection2)
XCTAssertEqual(collection.events.count, 3)
XCTAssertEqual(ctx.tracing?.events.count, 3)
}
}