Skip to content

Commit a7224bf

Browse files
authored
Merge branch 'main' into LoggingSDK
2 parents 004a29d + 444d981 commit a7224bf

File tree

14 files changed

+329
-26
lines changed

14 files changed

+329
-26
lines changed

CODEOWNERS

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414

1515
# Maintainers: @SergeyKanzhelev @nachoBonafonte
1616

17-
# Approvers: @bryce-b
17+
# Approvers: @bryce-b @vvydier
1818

1919

20-
* @SergeyKanzhelev @nachoBonafonte @bryce-b
20+
* @SergeyKanzhelev @nachoBonafonte @bryce-b @vvydier
2121

2222
CODEOWNERS @SergeyKanzhelev @nachoBonafonte

Package.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ let package = Package(
6565
exclude: ["README.md"]),
6666
.target(name: "SwiftMetricsShim",
6767
dependencies: ["OpenTelemetrySdk",
68-
.product(name: "NIO", package: "swift-nio"),
6968
.product(name: "CoreMetrics", package: "swift-metrics")],
7069
path: "Sources/Importers/SwiftMetricsShim",
7170
exclude: ["README.md"]),

README.md

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,40 @@ or
3434
.target(name: "ExampleApp", dependencies: ["OpenTelemetrySdk"]),
3535
```
3636

37+
## Documentation
38+
39+
Official documentation for the library can be found in the official opentelemetry [documentation page](https://opentelemetry.io/docs/instrumentation/swift/), including:
40+
41+
* Documentation about installation and [manual instrumentation](https://opentelemetry.io/docs/instrumentation/swift/manual/)
42+
43+
* [Libraries](https://opentelemetry.io/docs/instrumentation/swift/libraries/) that provide automatic instrumentation
44+
3745
## Current status
38-
<!--Please note:
39-
Tracing spec follows version 1.0.1 and should be considered stable.
40-
Metrics support is in beta, and the spec is still not following latest approved spec.
41-
Semantic Conventions and OpenTracing shim are also experimental.
42-
-->
4346

44-
Currently Tracing, Metrics and Baggage API's and SDK are implemented, also OpenTracing shim, for compatibility with existing Opentracing code.
47+
### API and SDK
48+
49+
Tracing and Baggage should be considered stable
50+
51+
Metrics is implemented using an outdated spec, is fully functional but will change in the future
52+
53+
Logs are currently in development
54+
55+
### Supported exporters, importers and instrumentation libraries
56+
57+
#### Traces
58+
* Exporters: Stdout, Jaeger, Zipkin, Datadog and OpenTelemetry (OTLP) collector
59+
* Importers: OpenTracingShim
60+
61+
#### Metrics
62+
* Exporters: Prometheus, Datadog, and OpenTelemetry (OTLP) collector
63+
* Importers: SwiftMetricsShim
4564

46-
Implemented traces exporters: Stdout, Jaeger, Zipkin, Datadog and OpenTelemetry collector
65+
#### Instrumentation libraries
66+
* URLSession
67+
* NetworkStatus
68+
* SDKResourceExtension
69+
* SignPostIntegration
4770

48-
Implemented metrics exporters: Prometheus, Datadog, and OpenTelemetry collector
4971

5072
## Examples
5173

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
//===----------------------------------------------------------------------===//
7+
//
8+
// This source file is part of the Swift Metrics API open source project
9+
//
10+
// Copyright (c) 2018-2019 Apple Inc. and the Swift Metrics API project authors
11+
// Licensed under Apache License v2.0
12+
//
13+
// See LICENSE.txt for license information
14+
// See CONTRIBUTORS.txt for the list of Swift Metrics API project authors
15+
//
16+
// SPDX-License-Identifier: Apache-2.0
17+
//
18+
//===----------------------------------------------------------------------===//
19+
20+
//===----------------------------------------------------------------------===//
21+
//
22+
// This source file is part of the SwiftNIO open source project
23+
//
24+
// Copyright (c) 2017-2018 Apple Inc. and the SwiftNIO project authors
25+
// Licensed under Apache License v2.0
26+
//
27+
// See LICENSE.txt for license information
28+
// See CONTRIBUTORS.txt for the list of SwiftNIO project authors
29+
//
30+
// SPDX-License-Identifier: Apache-2.0
31+
//
32+
//===----------------------------------------------------------------------===//
33+
34+
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
35+
import Darwin
36+
#else
37+
import Glibc
38+
#endif
39+
40+
/// A threading lock based on `libpthread` instead of `libdispatch`.
41+
///
42+
/// This object provides a lock on top of a single `pthread_mutex_t`. This kind
43+
/// of lock is safe to use with `libpthread`-based threading models, such as the
44+
/// one used by NIO.
45+
internal final class Lock {
46+
fileprivate let mutex: UnsafeMutablePointer<pthread_mutex_t> = UnsafeMutablePointer.allocate(capacity: 1)
47+
48+
/// Create a new lock.
49+
public init() {
50+
let err = pthread_mutex_init(self.mutex, nil)
51+
precondition(err == 0, "pthread_mutex_init failed with error \(err)")
52+
}
53+
54+
deinit {
55+
let err = pthread_mutex_destroy(self.mutex)
56+
precondition(err == 0, "pthread_mutex_destroy failed with error \(err)")
57+
self.mutex.deallocate()
58+
}
59+
60+
/// Acquire the lock.
61+
///
62+
/// Whenever possible, consider using `withLock` instead of this method and
63+
/// `unlock`, to simplify lock handling.
64+
public func lock() {
65+
let err = pthread_mutex_lock(self.mutex)
66+
precondition(err == 0, "pthread_mutex_lock failed with error \(err)")
67+
}
68+
69+
/// Release the lock.
70+
///
71+
/// Whenever possible, consider using `withLock` instead of this method and
72+
/// `lock`, to simplify lock handling.
73+
public func unlock() {
74+
let err = pthread_mutex_unlock(self.mutex)
75+
precondition(err == 0, "pthread_mutex_unlock failed with error \(err)")
76+
}
77+
}
78+
79+
extension Lock {
80+
/// Acquire the lock for the duration of the given block.
81+
///
82+
/// This convenience method should be preferred to `lock` and `unlock` in
83+
/// most situations, as it ensures that the lock will be released regardless
84+
/// of how `body` exits.
85+
///
86+
/// - Parameter body: The block to execute while holding the lock.
87+
/// - Returns: The value returned by the block.
88+
@inlinable
89+
internal func withLock<T>(_ body: () throws -> T) rethrows -> T {
90+
self.lock()
91+
defer {
92+
self.unlock()
93+
}
94+
return try body()
95+
}
96+
97+
// specialise Void return (for performance)
98+
@inlinable
99+
internal func withLockVoid(_ body: () throws -> Void) rethrows {
100+
try self.withLock(body)
101+
}
102+
}
103+
104+
/// A threading lock based on `libpthread` instead of `libdispatch`.
105+
///
106+
/// This object provides a lock on top of a single `pthread_mutex_t`. This kind
107+
/// of lock is safe to use with `libpthread`-based threading models, such as the
108+
/// one used by NIO.
109+
internal final class ReadWriteLock {
110+
fileprivate let rwlock: UnsafeMutablePointer<pthread_rwlock_t> = UnsafeMutablePointer.allocate(capacity: 1)
111+
112+
/// Create a new lock.
113+
public init() {
114+
let err = pthread_rwlock_init(self.rwlock, nil)
115+
precondition(err == 0, "pthread_rwlock_init failed with error \(err)")
116+
}
117+
118+
deinit {
119+
let err = pthread_rwlock_destroy(self.rwlock)
120+
precondition(err == 0, "pthread_rwlock_destroy failed with error \(err)")
121+
self.rwlock.deallocate()
122+
}
123+
124+
/// Acquire a reader lock.
125+
///
126+
/// Whenever possible, consider using `withLock` instead of this method and
127+
/// `unlock`, to simplify lock handling.
128+
public func lockRead() {
129+
let err = pthread_rwlock_rdlock(self.rwlock)
130+
precondition(err == 0, "pthread_rwlock_rdlock failed with error \(err)")
131+
}
132+
133+
/// Acquire a writer lock.
134+
///
135+
/// Whenever possible, consider using `withLock` instead of this method and
136+
/// `unlock`, to simplify lock handling.
137+
public func lockWrite() {
138+
let err = pthread_rwlock_wrlock(self.rwlock)
139+
precondition(err == 0, "pthread_rwlock_wrlock failed with error \(err)")
140+
}
141+
142+
/// Release the lock.
143+
///
144+
/// Whenever possible, consider using `withLock` instead of this method and
145+
/// `lock`, to simplify lock handling.
146+
public func unlock() {
147+
let err = pthread_rwlock_unlock(self.rwlock)
148+
precondition(err == 0, "pthread_rwlock_unlock failed with error \(err)")
149+
}
150+
}
151+
152+
extension ReadWriteLock {
153+
/// Acquire the reader lock for the duration of the given block.
154+
///
155+
/// This convenience method should be preferred to `lock` and `unlock` in
156+
/// most situations, as it ensures that the lock will be released regardless
157+
/// of how `body` exits.
158+
///
159+
/// - Parameter body: The block to execute while holding the lock.
160+
/// - Returns: The value returned by the block.
161+
@inlinable
162+
internal func withReaderLock<T>(_ body: () throws -> T) rethrows -> T {
163+
self.lockRead()
164+
defer {
165+
self.unlock()
166+
}
167+
return try body()
168+
}
169+
170+
/// Acquire the writer lock for the duration of the given block.
171+
///
172+
/// This convenience method should be preferred to `lock` and `unlock` in
173+
/// most situations, as it ensures that the lock will be released regardless
174+
/// of how `body` exits.
175+
///
176+
/// - Parameter body: The block to execute while holding the lock.
177+
/// - Returns: The value returned by the block.
178+
@inlinable
179+
internal func withWriterLock<T>(_ body: () throws -> T) rethrows -> T {
180+
self.lockWrite()
181+
defer {
182+
self.unlock()
183+
}
184+
return try body()
185+
}
186+
187+
// specialise Void return (for performance)
188+
@inlinable
189+
internal func withReaderLockVoid(_ body: () throws -> Void) rethrows {
190+
try self.withReaderLock(body)
191+
}
192+
193+
// specialise Void return (for performance)
194+
@inlinable
195+
internal func withWriterLockVoid(_ body: () throws -> Void) rethrows {
196+
try self.withWriterLock(body)
197+
}
198+
}

Sources/Importers/SwiftMetricsShim/SwiftMetricsShim.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
*/
55

66
import CoreMetrics
7-
import NIOConcurrencyHelpers
87
import OpenTelemetryApi
98

109
public class OpenTelemetrySwiftMetrics: MetricsFactory {

Sources/Instrumentation/URLSession/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ This behaviour can be modified or augmented by using the optional callbacks defi
1919

2020
`nameSpan: ((URLRequest) -> (String)?)?` - Modifies the name for the given request instead of stantard Opentelemetry name
2121

22+
`spanCustomization: ((URLRequest, SpanBuilder) -> Void)?` - Customizes the span while it's being built, such as by adding a parent, a link, attributes, etc.
23+
2224
`createdRequest: ((URLRequest, Span) -> Void)?` - Called after request is created, it allows to add extra information to the Span
2325

2426
`receivedResponse: ((URLResponse, DataOrFile?, Span) -> Void)?`- Called after response is received, it allows to add extra information to the Span

Sources/Instrumentation/URLSession/URLSessionInstrumentationConfiguration.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ public struct URLSessionInstrumentationConfiguration {
1515
public init(shouldRecordPayload: ((URLSession) -> (Bool)?)? = nil,
1616
shouldInstrument: ((URLRequest) -> (Bool)?)? = nil,
1717
nameSpan: ((URLRequest) -> (String)?)? = nil,
18+
spanCustomization: ((URLRequest, SpanBuilder) -> Void)? = nil,
1819
shouldInjectTracingHeaders: ((URLRequest) -> (Bool)?)? = nil,
1920
injectCustomHeaders: ((inout URLRequest, Span?) -> Void)? = nil,
2021
createdRequest: ((URLRequest, Span) -> Void)? = nil,
@@ -26,6 +27,7 @@ public struct URLSessionInstrumentationConfiguration {
2627
self.shouldInjectTracingHeaders = shouldInjectTracingHeaders
2728
self.injectCustomHeaders = injectCustomHeaders
2829
self.nameSpan = nameSpan
30+
self.spanCustomization = spanCustomization
2931
self.createdRequest = createdRequest
3032
self.receivedResponse = receivedResponse
3133
self.receivedError = receivedError
@@ -52,6 +54,9 @@ public struct URLSessionInstrumentationConfiguration {
5254
/// default name: `HTTP {method}` e.g. `HTTP PUT`
5355
public var nameSpan: ((URLRequest) -> (String)?)?
5456

57+
/// Implement this callback to customize the span, such as by adding a parent, a link, attributes, etc
58+
public var spanCustomization: ((URLRequest, SpanBuilder) -> Void)?
59+
5560
/// Called before the span is created, it allows to add extra information to the Span
5661
public var createdRequest: ((URLRequest, Span) -> Void)?
5762

Sources/Instrumentation/URLSession/URLSessionLogger.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ class URLSessionLogger {
7171
attributes.forEach {
7272
spanBuilder.setAttribute(key: $0.key, value: $0.value)
7373
}
74+
instrumentation.configuration.spanCustomization?(request, spanBuilder)
7475

7576
let span = spanBuilder.startSpan()
7677
runningSpansQueue.sync {

Sources/OpenTelemetryApi/Context/ActivityContextManager.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ class ActivityContextManager: ContextManager {
2828
}
2929

3030
var objectScope = NSMapTable<AnyObject, ScopeElement>(keyOptions: .weakMemory, valueOptions: .strongMemory)
31-
3231
var contextMap = [os_activity_id_t: [String: AnyObject]]()
3332

3433
func getCurrentContextValue(forKey key: OpenTelemetryContextKeys) -> AnyObject? {
@@ -69,6 +68,13 @@ class ActivityContextManager: ContextManager {
6968
}
7069

7170
func removeContextValue(forKey key: OpenTelemetryContextKeys, value: AnyObject) {
71+
let activityIdent = os_activity_get_identifier(OS_ACTIVITY_CURRENT, nil)
72+
rlock.lock()
73+
contextMap[activityIdent]?[key.rawValue] = nil
74+
if contextMap[activityIdent]?.isEmpty ?? false {
75+
contextMap[activityIdent] = nil
76+
}
77+
rlock.unlock()
7278
if let scope = objectScope.object(forKey: value) {
7379
var scope = scope.scope
7480
os_activity_scope_leave(&scope)

Sources/OpenTelemetryApi/Trace/PropagatedSpan.swift

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import Foundation
88
/// The PropagatedSpan is the default Span that is used when no Span
99
/// implementation is available. All operations are no-op except context propagation.
1010
class PropagatedSpan: Span {
11-
var name: String = ""
11+
var name: String
1212

1313
var kind: SpanKind
1414

@@ -25,23 +25,40 @@ class PropagatedSpan: Span {
2525
/// Returns a DefaultSpan with an invalid SpanContext.
2626
convenience init() {
2727
let invalidContext = SpanContext.create(traceId: TraceId(),
28-
spanId: SpanId(),
29-
traceFlags: TraceFlags(),
30-
traceState: TraceState())
31-
self.init(context: invalidContext, kind: .client)
28+
spanId: SpanId(),
29+
traceFlags: TraceFlags(),
30+
traceState: TraceState())
31+
self.init(name: "", context: invalidContext, kind: .client)
3232
}
3333

3434
/// Creates an instance of this class with the SpanContext.
3535
/// - Parameter context: the SpanContext
3636
convenience init(context: SpanContext) {
37-
self.init(context: context, kind: .client)
37+
self.init(name: "", context: context, kind: .client)
3838
}
3939

4040
/// Creates an instance of this class with the SpanContext and Span kind
4141
/// - Parameters:
4242
/// - context: the SpanContext
4343
/// - kind: the SpanKind
44-
init(context: SpanContext, kind: SpanKind) {
44+
convenience init(context: SpanContext, kind: SpanKind) {
45+
self.init(name: "", context: context, kind: kind)
46+
}
47+
48+
/// Creates an instance of this class with the SpanContext and Span name
49+
/// - Parameters:
50+
/// - context: the SpanContext
51+
/// - kind: the SpanKind
52+
convenience init(name: String, context: SpanContext) {
53+
self.init(name: name, context: context, kind: .client)
54+
}
55+
56+
/// Creates an instance of this class with the SpanContext, Span kind and name
57+
/// - Parameters:
58+
/// - context: the SpanContext
59+
/// - kind: the SpanKind
60+
init(name: String, context: SpanContext, kind: SpanKind) {
61+
self.name = name
4562
self.context = context
4663
self.kind = kind
4764
}

0 commit comments

Comments
 (0)