diff --git a/Examples/SmokeTest/SmokeTest/ContentView.swift b/Examples/SmokeTest/SmokeTest/ContentView.swift index fe09d6a..bb4d4f5 100644 --- a/Examples/SmokeTest/SmokeTest/ContentView.swift +++ b/Examples/SmokeTest/SmokeTest/ContentView.swift @@ -31,34 +31,18 @@ private func flush() { Thread.sleep(forTimeInterval: 3.0) } -struct InstrumentedView: View { - private let creationDate: Date - private let content: () -> Content - - init(@SwiftUICore.ViewBuilder _ content: @escaping () -> Content) { - self.creationDate = Date() - self.content = content - } - - var body: some View { - content() - .onAppear { - let interval = Date().timeIntervalSince(creationDate) - print("render time: \(interval)") - } - } -} - struct ContentView: View { var body: some View { - InstrumentedView { + HoneycombInstrumentedView(name: "main view") { VStack( alignment: .center, spacing: 20.0 ) { - Image(systemName: "globe") - .imageScale(.large) - .foregroundStyle(.tint) + HoneycombInstrumentedView(name: "home icon") { + Image(systemName: "globe") + .imageScale(.large) + .foregroundStyle(.tint) + } Text("This is a sample app.") @@ -77,14 +61,18 @@ struct ContentView: View { } .buttonStyle(.bordered) - Text(String(timeConsumingCalculation())) + HoneycombInstrumentedView(name: "expensive text") { + Text(String(timeConsumingCalculation())) + } + } .padding() } } private func timeConsumingCalculation() -> Int { - (1...10_000_000).reduce(0, +) + print("starting time consuming calculation") + return (1...100_000_000).reduce(0, +) } } diff --git a/Sources/Honeycomb/HoneycombInstrumentedView.swift b/Sources/Honeycomb/HoneycombInstrumentedView.swift new file mode 100644 index 0000000..ebdfd27 --- /dev/null +++ b/Sources/Honeycomb/HoneycombInstrumentedView.swift @@ -0,0 +1,55 @@ +import OpenTelemetryApi +import OpenTelemetrySdk +import SwiftUI + +private let honeycombInstrumentedViewName = "@honeycombio/instrumentation-view" + +struct HoneycombInstrumentedView: View { + private let span: Span + private let content: () -> Content + private let name: String + + init(name: String, @SwiftUICore.ViewBuilder _ content: @escaping () -> Content) { + self.name = name + self.content = content + + span = getMetricKitTracer().spanBuilder(spanName: "ViewInstrumentation") + .setStartTime(time: Date()) + .setAttribute(key: "ViewName", value: name) + .startSpan() + + print("\(name) init") + } + + var body: some View { + print("\(name) started rendering") + let start = Date() + + let c = content() + + print("\(name) finished rendering") + span.setAttribute( + key: "RenderTimeMicroSeconds", + value: Int(Date().timeIntervalSince(start).toMicroseconds) + ) + + return c.onAppear { + span.end(time: Date()) + } + } +} + +extension View { + func honeycombInstrumentedView(name: String) -> some View { + HoneycombInstrumentedView(name: name) { + self + } + } +} + +func getViewTracer() -> Tracer { + return OpenTelemetry.instance.tracerProvider.get( + instrumentationName: honeycombInstrumentedViewName, + instrumentationVersion: honeycombLibraryVersion + ) +}