Skip to content

Commit 9366f86

Browse files
froseioc0mtru1se
andauthored
DEMRUM-421: Log to span translation (#267)
* DEMRUM-421: Log to span translation * warning fix * Log to span event processor * fix project * Log to span exporter * fix merge conflict * finalize log to span * body is body * fix mr comments * fix after merge * chore: Properly update all resolved deps * fix: Fix CiscoLogger and SplunkCommon integration issues --------- Co-authored-by: Martin Budinsky <[email protected]>
1 parent b133fa7 commit 9366f86

File tree

4 files changed

+110
-14
lines changed

4 files changed

+110
-14
lines changed

Splunk.xcworkspace/xcshareddata/swiftpm/Package.resolved

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

SplunkAgent/SplunkAgent.xcodeproj/project.pbxproj

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@
215215
C791AE002DAE8B81002AAA2B /* KeyBuilder+DefaultKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = C791ADFF2DAE8B81002AAA2B /* KeyBuilder+DefaultKeys.swift */; };
216216
C791AE022DAE8B99002AAA2B /* CiscoDiskStorage in Frameworks */ = {isa = PBXBuildFile; productRef = C791AE012DAE8B99002AAA2B /* CiscoDiskStorage */; };
217217
C7A2BD1B2BB45363005D4CFB /* AppStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7A2BD1A2BB45363005D4CFB /* AppStateModel.swift */; };
218+
C7C112672DB8D64C00B8E893 /* OTLPLogToSpanExporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7C112652DB8D64C00B8E893 /* OTLPLogToSpanExporter.swift */; };
218219
C7FFC4F52B7662E30035203B /* Service.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7FFC4F42B7662E30035203B /* Service.swift */; };
219220
E4032E622B552343003D4392 /* DefaultSessionTestBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4032E612B552343003D4392 /* DefaultSessionTestBuilder.swift */; };
220221
E4032E642B55278C003D4392 /* PersistentSessionsValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4032E632B55278C003D4392 /* PersistentSessionsValidator.swift */; };
@@ -795,6 +796,7 @@
795796
C76AB8DD2B7B7A2400CB4307 /* AlternativeRemoteConfiguration.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = AlternativeRemoteConfiguration.json; sourceTree = "<group>"; };
796797
C791ADFF2DAE8B81002AAA2B /* KeyBuilder+DefaultKeys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "KeyBuilder+DefaultKeys.swift"; sourceTree = "<group>"; };
797798
C7A2BD1A2BB45363005D4CFB /* AppStateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppStateModel.swift; sourceTree = "<group>"; };
799+
C7C112652DB8D64C00B8E893 /* OTLPLogToSpanExporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OTLPLogToSpanExporter.swift; sourceTree = "<group>"; };
798800
C7FFC4F42B7662E30035203B /* Service.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Service.swift; sourceTree = "<group>"; };
799801
E4032E612B552343003D4392 /* DefaultSessionTestBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultSessionTestBuilder.swift; sourceTree = "<group>"; };
800802
E4032E632B55278C003D4392 /* PersistentSessionsValidator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersistentSessionsValidator.swift; sourceTree = "<group>"; };
@@ -2004,6 +2006,7 @@
20042006
2A2926342DAD114900AB6F03 /* Attribute Checker Exporters */,
20052007
4B5A5CA82D60ED3D009DA0D5 /* Utils */,
20062008
4B5A5CA92D60ED3D009DA0D5 /* OTel.swift */,
2009+
C7C112662DB8D64C00B8E893 /* LogToSpanExporter */,
20072010
);
20082011
path = SplunkOpenTelemetry;
20092012
sourceTree = "<group>";
@@ -2490,6 +2493,14 @@
24902493
path = Model;
24912494
sourceTree = "<group>";
24922495
};
2496+
C7C112662DB8D64C00B8E893 /* LogToSpanExporter */ = {
2497+
isa = PBXGroup;
2498+
children = (
2499+
C7C112652DB8D64C00B8E893 /* OTLPLogToSpanExporter.swift */,
2500+
);
2501+
path = LogToSpanExporter;
2502+
sourceTree = "<group>";
2503+
};
24932504
E405497D2DACF57500B7A2E4 /* User */ = {
24942505
isa = PBXGroup;
24952506
children = (
@@ -4322,6 +4333,7 @@
43224333
2A2926372DAD11C800AB6F03 /* AttributeCheckerLogExporter.swift in Sources */,
43234334
E4A537422DA655E2002323E2 /* OLTPAttributesSpanProcessor.swift in Sources */,
43244335
4B96421A2D61375E009A2E7F /* OTel.swift in Sources */,
4336+
C7C112672DB8D64C00B8E893 /* OTLPLogToSpanExporter.swift in Sources */,
43254337
2A5949DB2DA3FC2100F2E857 /* SplunkStdoutSpanExporter.swift in Sources */,
43264338
2A5949DC2DA3FC2100F2E857 /* SplunkStdoutLogExporter.swift in Sources */,
43274339
2A2926352DAD114900AB6F03 /* AttributeCheckerSpanExporter.swift in Sources */,

SplunkOpenTelemetry/Sources/SplunkOpenTelemetry/Log Event Processor/OTLPLogEventProcessor.swift

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,16 +56,10 @@ public class OTLPLogEventProcessor: LogEventProcessor {
5656
let configuration = OtlpConfiguration()
5757
let envVarHeaders = [(String, String)]()
5858

59-
// Initialize background exporter
60-
let backgroundLogExporter = OTLPBackgroundHTTPLogExporter(
61-
endpoint: logsEndpoint,
62-
config: configuration,
63-
qosConfig: SessionQOSConfiguration(),
64-
envVarHeaders: envVarHeaders
65-
)
59+
let logToSpanExporter = OTLPLogToSpanExporter(agentVersion: resources.agentVersion)
6660

6761
// Initialize attribute checker proxy exporter
68-
let attributeCheckerExporter = AttributeCheckerLogExporter(proxy: backgroundLogExporter)
62+
let attributeCheckerExporter = AttributeCheckerLogExporter(proxy: logToSpanExporter)
6963

7064
// Initialize LogRecordProcessor
7165
let simpleLogRecordProcessor = SimpleLogRecordProcessor(
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
//
2+
/*
3+
Copyright 2025 Splunk Inc.
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
*/
17+
18+
internal import CiscoLogger
19+
import Foundation
20+
import OpenTelemetryProtocolExporterCommon
21+
import OpenTelemetrySdk
22+
import OpenTelemetryApi
23+
import SplunkCommon
24+
25+
public class OTLPLogToSpanExporter: LogRecordExporter {
26+
27+
// MARK: - Private properties
28+
29+
private let agentVersion: String
30+
31+
// Internal Logger
32+
private let logger = DefaultLogAgent(poolName: PackageIdentifier.instance(), category: "Log to Span Exporter")
33+
34+
35+
// MARK: - Initialization
36+
37+
init(agentVersion: String) {
38+
self.agentVersion = agentVersion
39+
}
40+
41+
42+
// MARK: - LogRecordExporter protocol implementation
43+
44+
public func export(logRecords: [OpenTelemetrySdk.ReadableLogRecord], explicitTimeout: TimeInterval?) -> OpenTelemetrySdk.ExportResult {
45+
46+
let tracer = OpenTelemetry.instance
47+
.tracerProvider
48+
.get(
49+
instrumentationName: "LogToSpan",
50+
instrumentationVersion: agentVersion
51+
)
52+
53+
for log in logRecords {
54+
55+
guard
56+
let spanName = spanName(from: log),
57+
!spanName.isEmpty
58+
else {
59+
logger.log(level: .error) {
60+
"Missing span name for log record"
61+
}
62+
continue
63+
}
64+
65+
let span = tracer
66+
.spanBuilder(spanName: spanName)
67+
.setStartTime(time: log.timestamp)
68+
.startSpan()
69+
70+
for (key, value) in log.attributes {
71+
span.setAttribute(key: key, value: value)
72+
}
73+
74+
span.setAttribute(key: "body", value: log.body)
75+
76+
span.end(time: log.timestamp)
77+
}
78+
return .success
79+
}
80+
81+
private func spanName(from log: ReadableLogRecord) -> String? {
82+
return log.attributes["event.name"]?.description
83+
}
84+
85+
public func shutdown(explicitTimeout: TimeInterval?) {}
86+
87+
public func forceFlush(explicitTimeout: TimeInterval?) -> OpenTelemetrySdk.ExportResult {
88+
return .success
89+
}
90+
}

0 commit comments

Comments
 (0)