-
Notifications
You must be signed in to change notification settings - Fork 175
/
Copy pathActivityContextManager.swift
97 lines (84 loc) · 3.41 KB
/
ActivityContextManager.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
import Foundation
#if canImport(os.activity)
import os.activity
// Bridging Obj-C variabled defined as c-macroses. See `activity.h` header.
// swiftlint:disable identifier_name
private let OS_ACTIVITY_CURRENT = unsafeBitCast(dlsym(UnsafeMutableRawPointer(bitPattern: -2), "_os_activity_current"),
to: os_activity_t.self)
// swiftlint:enable identifier_name
@_silgen_name("_os_activity_create") private func _os_activity_create(
_ dso: UnsafeRawPointer?,
_ description: UnsafePointer<Int8>,
_ parent: Unmanaged<AnyObject>?,
_ flags: os_activity_flag_t
) -> AnyObject!
class ActivityContextManager: ImperativeContextManager {
static let instance = ActivityContextManager()
let rlock = NSRecursiveLock()
class ScopeElement {
init(scope: os_activity_scope_state_s) {
self.scope = scope
}
var scope: os_activity_scope_state_s
}
var objectScope = NSMapTable<AnyObject, ScopeElement>(keyOptions: .weakMemory, valueOptions: .strongMemory)
var contextMap = [os_activity_id_t: [String: AnyObject]]()
func getCurrentContextValue(forKey key: OpenTelemetryContextKeys)
-> AnyObject? {
var parentIdent: os_activity_id_t = 0
let activityIdent = os_activity_get_identifier(OS_ACTIVITY_CURRENT, &parentIdent)
var contextValue: AnyObject?
rlock.lock()
guard let context = contextMap[activityIdent] ?? contextMap[parentIdent]
else {
rlock.unlock()
return nil
}
contextValue = context[key.rawValue]
rlock.unlock()
return contextValue
}
func setCurrentContextValue(forKey key: OpenTelemetryContextKeys, value: AnyObject) {
var parentIdent: os_activity_id_t = 0
var activityIdent = os_activity_get_identifier(OS_ACTIVITY_CURRENT, &parentIdent)
rlock.lock()
if contextMap[activityIdent] == nil
|| contextMap[activityIdent]?[key.rawValue] != nil {
var scope: os_activity_scope_state_s
(activityIdent, scope) = createActivityContext()
contextMap[activityIdent] = [String: AnyObject]()
objectScope.setObject(ScopeElement(scope: scope), forKey: value)
}
contextMap[activityIdent]?[key.rawValue] = value
rlock.unlock()
}
func createActivityContext() -> (os_activity_id_t, os_activity_scope_state_s) {
let dso = UnsafeMutableRawPointer(mutating: #dsohandle)
let activity = _os_activity_create(dso, "ActivityContext", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT)
let currentActivityId = os_activity_get_identifier(activity, nil)
var activityState = os_activity_scope_state_s()
os_activity_scope_enter(activity, &activityState)
return (currentActivityId, activityState)
}
func removeContextValue(forKey key: OpenTelemetryContextKeys, value: AnyObject) {
rlock.lock()
for (activityKey, activity) in contextMap
where value === activity[key.rawValue] {
contextMap[activityKey]?[key.rawValue] = nil
if contextMap[activityKey]?.isEmpty ?? false {
contextMap[activityKey] = nil
}
}
if let scope = objectScope.object(forKey: value) {
var scope = scope.scope
os_activity_scope_leave(&scope)
objectScope.removeObject(forKey: value)
}
rlock.unlock()
}
}
#endif