Skip to content
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

Add Opentracing shims #45

Merged
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
5 changes: 5 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ let package = Package(
.library( name: "libOpenTelemetryApi", type: .static, targets: ["OpenTelemetryApi"]),
.library( name: "OpenTelemetrySdk", type: .dynamic, targets: ["OpenTelemetrySdk"]),
.library( name: "libOpenTelemetrySdk", type: .static, targets: ["OpenTelemetrySdk"]),
.library( name: "OpenTracingShim", type: .dynamic, targets: ["OpenTracingShim"]),
.library( name: "libOpenTracingShim", type: .static, targets: ["OpenTracingShim"]),
.library( name: "JaegerExporter", type: .dynamic, targets: ["JaegerExporter"]),
.library( name: "libJaegerExporter", type: .static, targets: ["JaegerExporter"]),
.library( name: "StdoutExporter", type: .dynamic, targets: ["StdoutExporter"]),
Expand All @@ -25,13 +27,16 @@ let package = Package(
.executable(name: "loggingTracer", targets: ["LoggingTracer"]),
],
dependencies: [
.package(url: "https://github.com/undefinedlabs/opentracing-objc", .branch("spm-support")), // Need custom fork because of SPM
.package(url: "https://github.com/undefinedlabs/Thrift-Swift", from: "1.1.1"), // Need custom fork because of SPM
.package(url: "https://github.com/apple/swift-nio.git", from: "2.0.0"),
],
targets: [
.target( name: "OpenTelemetryApi", dependencies: []),
.testTarget( name: "OpenTelemetryApiTests", dependencies: ["OpenTelemetryApi"], path: "Tests/OpenTelemetryApiTests"),
.target( name: "OpenTelemetrySdk", dependencies: ["OpenTelemetryApi"]),
.target( name: "OpenTracingShim", dependencies: ["OpenTelemetrySdk", "libOpentracing"]),
.testTarget( name: "OpenTracingShimTests", dependencies: ["OpenTracingShim", "OpenTelemetrySdk"], path: "Tests/OpenTracingShim"),
.testTarget( name: "OpenTelemetrySdkTests", dependencies: ["OpenTelemetryApi", "OpenTelemetrySdk"], path: "Tests/OpenTelemetrySdkTests"),
.target( name: "JaegerExporter", dependencies: ["OpenTelemetrySdk", "Thrift"], path: "Sources/Exporters/Jaeger"),
.testTarget( name: "JaegerExporterTests", dependencies: ["JaegerExporter"], path: "Tests/ExportersTests/Jaeger"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,8 @@ public protocol CorrelationContext: AnyObject {
/// - Parameter key: entry key to return the value for.
func getEntryValue(key: EntryKey) -> EntryValue?
}

public func == (lhs: CorrelationContext, rhs: CorrelationContext) -> Bool {
guard type(of: lhs) == type(of: rhs) else { return false }
return lhs.getEntries() == rhs.getEntries()
}
6 changes: 5 additions & 1 deletion Sources/OpenTelemetryApi/Trace/EndSpanOptions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,9 @@ import Foundation
/// overriding the endTimestamp.
public struct EndSpanOptions {
/// The end timestamp
public var timestamp: Int64 = 0
public init(timestamp: Int64 = 0 ) {
self.timestamp = timestamp
}

public private(set) var timestamp: Int64
}
12 changes: 11 additions & 1 deletion Sources/OpenTelemetryApi/Trace/Span.swift
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,16 @@ extension Span {
}
}

extension Span {
public func hash(into hasher: inout Hasher) {
hasher.combine(context.spanId)
}

public static func == (lhs: Span, rhs: Span) -> Bool {
return lhs.context.spanId == rhs.context.spanId
}
}

extension Span {
public func setAttribute(key: String, value: String) {
return setAttribute(key: key, value: AttributeValue.string(value))
Expand All @@ -117,7 +127,7 @@ extension Span {
public func setAttribute(key: String, value: Bool) {
return setAttribute(key: key, value: AttributeValue.bool(value))
}

public func setAttribute(key: SemanticAttributes, value: String) {
return setAttribute(key: key.rawValue, value: AttributeValue.string(value))
}
Expand Down
6 changes: 5 additions & 1 deletion Sources/OpenTelemetryApi/Trace/SpanContext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import Foundation
/// A class that represents a span context. A span context contains the state that must propagate to
/// child Spans and across process boundaries. It contains the identifiers race_id and span_id
/// associated with the Span and a set of options.
public final class SpanContext: Equatable, CustomStringConvertible {
public final class SpanContext: Equatable, CustomStringConvertible, Hashable {
/// The trace identifier associated with this SpanContext
public private(set) var traceId: TraceId

Expand Down Expand Up @@ -99,4 +99,8 @@ public final class SpanContext: Equatable, CustomStringConvertible {
public var description: String {
return "SpanContext{traceId=\(traceId), spanId=\(spanId), traceFlags=\(traceFlags)}, isRemote=\(isRemote)"
}

public func hash(into hasher: inout Hasher) {
hasher.combine(spanId)
}
}
6 changes: 6 additions & 0 deletions Sources/OpenTelemetryApi/Trace/TracerProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,9 @@ public protocol TracerProvider {
/// - instrumentationVersion: The version of the instrumentation library (e.g., "semver:1.0.0"). Optional
func get(instrumentationName: String, instrumentationVersion: String?) -> Tracer
}

extension TracerProvider {
func get(instrumentationName: String) -> Tracer {
return get(instrumentationName: instrumentationName, instrumentationVersion: nil)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ import OpenTelemetryApi

/// CorrelationContextManagerSdk is SDK implementation of CorrelationContextManager.
public class CorrelationContextManagerSdk: CorrelationContextManager {
public init() {
}

public func contextBuilder() -> CorrelationContextBuilder {
return CorrelationContextSdkBuilder()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ public class CorrelationContextSdkBuilder: CorrelationContextBuilder {
var noImplicitParent: Bool = false
var entries = [EntryKey: Entry?]()

public init() {
}

@discardableResult public func setParent(_ parent: CorrelationContext) -> Self {
self.parent = parent
return self
Expand Down
8 changes: 6 additions & 2 deletions Sources/OpenTelemetrySdk/OpenTelemetrySdk.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,18 @@ public struct OpenTelemetrySDK {
return OpenTelemetry.instance.tracerProvider as! TracerSdkProvider
}

public var meter: MeterSdkProvider {
public var meterProvider: MeterSdkProvider {
return OpenTelemetry.instance.meterProvider as! MeterSdkProvider
}

public var correlationContextManager: CorrelationContextManagerSdk {
public var contextManager: CorrelationContextManagerSdk {
return OpenTelemetry.instance.contextManager as! CorrelationContextManagerSdk
}

public var propagators: ContextPropagators {
return OpenTelemetry.instance.propagators
}

private init() {
OpenTelemetry.registerTracerProvider(tracerProvider: TracerSdkProvider())
OpenTelemetry.registerMeterProvider(meterProvider: MeterSdkProvider())
Expand Down
39 changes: 39 additions & 0 deletions Sources/OpenTracingShim/BaseShimProtocol.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright 2020, OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import Foundation
import OpenTelemetryApi

protocol BaseShimProtocol {
var telemetryInfo: TelemetryInfo { get }
}

extension BaseShimProtocol {
var tracer: Tracer {
return telemetryInfo.tracer
}

var spanContextTable: SpanContextShimTable {
return telemetryInfo.spanContextTable
}

var contextManager: CorrelationContextManager {
return telemetryInfo.contextManager
}

var propagators: ContextPropagators {
return telemetryInfo.propagators
}
}
208 changes: 208 additions & 0 deletions Sources/OpenTracingShim/Locks.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
// Copyright 2020, OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift Metrics API open source project
//
// Copyright (c) 2018-2019 Apple Inc. and the Swift Metrics API project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of Swift Metrics API project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftNIO open source project
//
// Copyright (c) 2017-2018 Apple Inc. and the SwiftNIO project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of SwiftNIO project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
import Darwin
#else
import Glibc
#endif

/// A threading lock based on `libpthread` instead of `libdispatch`.
///
/// This object provides a lock on top of a single `pthread_mutex_t`. This kind
/// of lock is safe to use with `libpthread`-based threading models, such as the
/// one used by NIO.
internal final class Lock {
fileprivate let mutex: UnsafeMutablePointer<pthread_mutex_t> = UnsafeMutablePointer.allocate(capacity: 1)

/// Create a new lock.
public init() {
let err = pthread_mutex_init(mutex, nil)
precondition(err == 0, "pthread_mutex_init failed with error \(err)")
}

deinit {
let err = pthread_mutex_destroy(self.mutex)
precondition(err == 0, "pthread_mutex_destroy failed with error \(err)")
self.mutex.deallocate()
}

/// Acquire the lock.
///
/// Whenever possible, consider using `withLock` instead of this method and
/// `unlock`, to simplify lock handling.
public func lock() {
let err = pthread_mutex_lock(mutex)
precondition(err == 0, "pthread_mutex_lock failed with error \(err)")
}

/// Release the lock.
///
/// Whenever possible, consider using `withLock` instead of this method and
/// `lock`, to simplify lock handling.
public func unlock() {
let err = pthread_mutex_unlock(mutex)
precondition(err == 0, "pthread_mutex_unlock failed with error \(err)")
}
}

extension Lock {
/// Acquire the lock for the duration of the given block.
///
/// This convenience method should be preferred to `lock` and `unlock` in
/// most situations, as it ensures that the lock will be released regardless
/// of how `body` exits.
///
/// - Parameter body: The block to execute while holding the lock.
/// - Returns: The value returned by the block.
@inlinable
internal func withLock<T>(_ body: () throws -> T) rethrows -> T {
lock()
defer {
self.unlock()
}
return try body()
}

// specialise Void return (for performance)
@inlinable
internal func withLockVoid(_ body: () throws -> Void) rethrows {
try withLock(body)
}
}

/// A threading lock based on `libpthread` instead of `libdispatch`.
///
/// This object provides a lock on top of a single `pthread_mutex_t`. This kind
/// of lock is safe to use with `libpthread`-based threading models, such as the
/// one used by NIO.
internal final class ReadWriteLock {
fileprivate let rwlock: UnsafeMutablePointer<pthread_rwlock_t> = UnsafeMutablePointer.allocate(capacity: 1)

/// Create a new lock.
public init() {
let err = pthread_rwlock_init(rwlock, nil)
precondition(err == 0, "pthread_rwlock_init failed with error \(err)")
}

deinit {
let err = pthread_rwlock_destroy(self.rwlock)
precondition(err == 0, "pthread_rwlock_destroy failed with error \(err)")
self.rwlock.deallocate()
}

/// Acquire a reader lock.
///
/// Whenever possible, consider using `withLock` instead of this method and
/// `unlock`, to simplify lock handling.
public func lockRead() {
let err = pthread_rwlock_rdlock(rwlock)
precondition(err == 0, "pthread_rwlock_rdlock failed with error \(err)")
}

/// Acquire a writer lock.
///
/// Whenever possible, consider using `withLock` instead of this method and
/// `unlock`, to simplify lock handling.
public func lockWrite() {
let err = pthread_rwlock_wrlock(rwlock)
precondition(err == 0, "pthread_rwlock_wrlock failed with error \(err)")
}

/// Release the lock.
///
/// Whenever possible, consider using `withLock` instead of this method and
/// `lock`, to simplify lock handling.
public func unlock() {
let err = pthread_rwlock_unlock(rwlock)
precondition(err == 0, "pthread_rwlock_unlock failed with error \(err)")
}
}

extension ReadWriteLock {
/// Acquire the reader lock for the duration of the given block.
///
/// This convenience method should be preferred to `lock` and `unlock` in
/// most situations, as it ensures that the lock will be released regardless
/// of how `body` exits.
///
/// - Parameter body: The block to execute while holding the lock.
/// - Returns: The value returned by the block.
@inlinable
internal func withReaderLock<T>(_ body: () throws -> T) rethrows -> T {
lockRead()
defer {
self.unlock()
}
return try body()
}

/// Acquire the writer lock for the duration of the given block.
///
/// This convenience method should be preferred to `lock` and `unlock` in
/// most situations, as it ensures that the lock will be released regardless
/// of how `body` exits.
///
/// - Parameter body: The block to execute while holding the lock.
/// - Returns: The value returned by the block.
@inlinable
internal func withWriterLock<T>(_ body: () throws -> T) rethrows -> T {
lockWrite()
defer {
self.unlock()
}
return try body()
}

// specialise Void return (for performance)
@inlinable
internal func withReaderLockVoid(_ body: () throws -> Void) rethrows {
try withReaderLock(body)
}

// specialise Void return (for performance)
@inlinable
internal func withWriterLockVoid(_ body: () throws -> Void) rethrows {
try withWriterLock(body)
}
}
Loading