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

Develop #6

Merged
merged 4 commits into from
Jul 9, 2020
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
35 changes: 33 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,10 +188,41 @@ public protocol XRayEmitter {
}
```

example:
example of an emitter which logs emitted segments:

```swift
let recorder = XRayRecorder(emitter: XRayNoopEmitter())
public struct XRayLogEmitter: XRayEmitter {
private let logger: Logger

private let encoder: JSONEncoder = {
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
return encoder
}()

public init(label: String? = nil) {
let label = label ?? "xray.log_emitter.\(String.random32())"
logger = Logger(label: label)
}

public func send(_ segment: XRayRecorder.Segment) {
do {
let document: String = try encoder.encode(segment)
logger.info("\n\(document)")
} catch {
logger.error("Failed to encode a segment: \(error)")
}
}

public func flush(_: @escaping (Error?) -> Void) {}
}
```


The emitter has to be provided when creating an instance of `XRayRecorder`:

```swift
let recorder = XRayRecorder(emitter: XRayNoOpEmitter())
```

## References
Expand Down
24 changes: 18 additions & 6 deletions Sources/AWSXRayRecorder/Config.swift
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
import Logging
import NIO // getenv

// TODO: document

private func env(_ name: String) -> String? {
guard let value = getenv(name) else { return nil }
return String(cString: value)
}

public extension XRayRecorder {
struct Config {
let enabled: Bool
Expand Down Expand Up @@ -46,3 +40,21 @@ internal extension XRayUDPEmitter {
}
}
}

#if canImport(Darwin)
import Darwin
#elseif canImport(Glibc)
import Glibc
#endif

private func env(_ name: String) -> String? {
#if canImport(Darwin)
guard let value = getenv(name) else { return nil }
return String(cString: value)
#elseif canImport(Glibc)
guard let value = getenv(name) else { return nil }
return String(cString: value)
#else
return nil
#endif
}
2 changes: 1 addition & 1 deletion Sources/AWSXRayRecorder/Emitter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ public protocol XRayEmitter {
func flush(_ callback: @escaping (Error?) -> Void)
}

public struct XRayNoopEmitter: XRayEmitter {
public struct XRayNoOpEmitter: XRayEmitter {
Copy link

Choose a reason for hiding this comment

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

👍

Copy link
Owner Author

Choose a reason for hiding this comment

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

;-) previous PR was more juicy, in fact should have been divided int osmaller ones

the examples gsoc-swift-tracing look nice, let me follow up on that in slashmo/gsoc-swift-tracing#36

Copy link

Choose a reason for hiding this comment

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

:-)

There's a WIP towards defining protocols for tracer instruments here (following open telemetry shape of API mostly): which may be of interest to you btw: slashmo/gsoc-swift-tracing#62

Thanks in advance, really looking forward to soon trying out xray with it the APIs.

public func send(_: XRayRecorder.Segment) {}
public func flush(_: @escaping (Error?) -> Void) {}

Expand Down
38 changes: 38 additions & 0 deletions Sources/AWSXRayRecorder/LogEmitter/LogEmitter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import Logging

import struct Foundation.Data
import class Foundation.JSONEncoder

private extension JSONEncoder {
func encode<T: Encodable>(_ value: T) throws -> String {
String(decoding: try encode(value), as: UTF8.self)
}
}

// TODO: document

public struct XRayLogEmitter: XRayEmitter {
private let logger: Logger

private let encoder: JSONEncoder = {
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
return encoder
}()

public init(label: String? = nil) {
let label = label ?? "xray.log_emitter.\(String.random32())"
logger = Logger(label: label)
}

public func send(_ segment: XRayRecorder.Segment) {
do {
let document: String = try encoder.encode(segment)
logger.info("\n\(document)")
} catch {
logger.error("Failed to encode a segment: \(error)")
}
}

public func flush(_: @escaping (Error?) -> Void) {}
}
20 changes: 11 additions & 9 deletions Sources/AWSXRayRecorder/Recorder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public class XRayRecorder {
public init(emitter: XRayEmitter, config: Config = Config()) {
self.config = config
if !config.enabled {
self.emitter = XRayNoopEmitter()
self.emitter = XRayNoOpEmitter()
} else {
self.emitter = emitter
}
Expand All @@ -32,7 +32,7 @@ public class XRayRecorder {

public convenience init(config: Config = Config(), eventLoopGroup: EventLoopGroup? = nil) {
if !config.enabled {
self.init(emitter: XRayNoopEmitter(), config: config)
self.init(emitter: XRayNoOpEmitter(), config: config)
} else {
do {
let emitter = try XRayUDPEmitter(config: .init(config), eventLoopGroup: eventLoopGroup)
Expand Down Expand Up @@ -116,17 +116,19 @@ public class XRayRecorder {
logger.debug("Segment \(id) parent has not been sent")
return
}
// mark it as emitted and pass responsibility to the emitter to actually do so
do {
// mark it as emitted and pass responsibility to the emitter to actually do so
try segment.emit()
// check if any of its subsegments are in progress and keep them in the recorder
let subsegments = segment.subsegmentsInProgress()
logger.debug("Segment \(id) has \(subsegments.count) subsegments \(Segment.State.inProgress)")
segmentsLock.withWriterLock {
subsegments.forEach { _segments[$0.id] = $0 }
}
// pass if the the emitter
emitter.send(segment)
} catch {
logger.error("Failed to emit Segment \(id): \(error)")
}
// check if any of its subsegments are in progress and keep them in the recorder
let subsegments = segment.subsegmentsInProgress()
logger.debug("Segment \(id) has \(subsegments.count) subsegments \(Segment.State.inProgress)")
subsegments.forEach { _segments[$0.id] = $0 }
// pass if the the emitter
emitter.send(segment)
}
}