diff --git a/.github/workflows/BuildAndTest.yml b/.github/workflows/BuildAndTest.yml index 6d6519c..e28147b 100644 --- a/.github/workflows/BuildAndTest.yml +++ b/.github/workflows/BuildAndTest.yml @@ -4,12 +4,12 @@ on: [push, pull_request, workflow_dispatch] jobs: macOS: - runs-on: macOS-13 + runs-on: macOS-latest steps: - uses: actions/checkout@v4 - uses: maxim-lobanov/setup-xcode@v1 with: - xcode-version: 15.1 + xcode-version: latest-stable - name: Build and Test for macOS run: swift test --enable-code-coverage - name: Upload Code coverage @@ -19,12 +19,12 @@ jobs: xcrun llvm-cov export -ignore-filename-regex="pb\.swift|grpc\.swift" -format="lcov" .build/debug/middleware-iosPackageTests.xctest/Contents/MacOS/middleware-iosPackageTests -instr-profile .build/debug/codecov/default.profdata > .build/debug/codecov/coverage_report.lcov ./codecov -f .build/debug/codecov/coverage_report.lcov iOS: - runs-on: macOS-13 + runs-on: macOS-latest steps: - uses: actions/checkout@v4 - uses: maxim-lobanov/setup-xcode@v1 with: - xcode-version: 15.1 + xcode-version: latest-stable - name: Install Homebrew kegs run: make setup-brew - name: Build for iOS @@ -32,12 +32,12 @@ jobs: - name: Test for iOS run: make test-without-building-ios tvOS: - runs-on: macOS-13 + runs-on: macOS-latest steps: - uses: actions/checkout@v4 - uses: maxim-lobanov/setup-xcode@v1 with: - xcode-version: 15.1 + xcode-version: - name: Install Homebrew kegs run: make setup-brew - name: Build for tvOS diff --git a/.github/workflows/Release.yml b/.github/workflows/Release.yml index f672a11..e8cacb1 100644 --- a/.github/workflows/Release.yml +++ b/.github/workflows/Release.yml @@ -9,12 +9,12 @@ on: jobs: release: - runs-on: macOS-13 + runs-on: macOS-latest steps: - uses: actions/checkout@v4 - uses: maxim-lobanov/setup-xcode@v1 with: - xcode-version: 15.1 + xcode-version: latest-stable - name: Install Homebrew kegs run: make setup-brew - name: Build for iOS diff --git a/Makefile b/Makefile index 19c9aed..9785732 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ PROJECT_NAME = "middleware-ios" XCODEBUILD_OPTIONS_IOS = \ -configuration Debug \ - -destination platform='iOS Simulator,name=iPhone 14,OS=latest' \ + -destination platform='iOS Simulator,name=iPhone 16,OS=latest' \ -scheme $(PROJECT_NAME) \ -workspace . @@ -14,7 +14,7 @@ XCODEBUILD_OPTIONS_TVOS = \ XCODEBUILD_OPTIONS_WATCHOS = \ -configuration Debug \ - -destination platform='watchOS Simulator,name=Apple Watch Series 8 (45mm),OS=latest' \ + -destination platform='watchOS Simulator,name=Apple Watch Series 10 (46mm),OS=latest' \ -scheme $(PROJECT_NAME) \ -workspace . @@ -32,7 +32,7 @@ build-tvos: .PHONY: build-watchos build-watchos: - set -o pipefail && xcodebuild $(XCODEBUILD_OPTIONS_IOS) build | xcbeautify + set -o pipefail && xcodebuild $(XCODEBUILD_OPTIONS_WATCHOS) build | xcbeautify .PHONY: build-for-testing-ios build-for-testing-ios: diff --git a/MiddlewareRum.podspec b/MiddlewareRum.podspec index f4253a3..f527982 100644 --- a/MiddlewareRum.podspec +++ b/MiddlewareRum.podspec @@ -16,7 +16,7 @@ Pod::Spec.new do |spec| # spec.name = "MiddlewareRum" - spec.version = "1.0.5" + spec.version = "1.0.6" spec.swift_version = "5.9" spec.summary = "Middleware iOS / MacOS / tvOS real user monitoring SDK" diff --git a/Package.resolved b/Package.resolved index bfcd050..e66a39c 100644 --- a/Package.resolved +++ b/Package.resolved @@ -23,8 +23,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/microsoft/plcrashreporter", "state" : { - "revision" : "1aed8f7dc79ce8e674c61e430ef51ca3db18cea9", - "version" : "1.11.1" + "revision" : "6752f71de206f6a53fa6a758c3660fd9a7fe7527", + "version" : "1.11.2" } }, { diff --git a/Package.swift b/Package.swift index a1f6229..6aae4bd 100644 --- a/Package.swift +++ b/Package.swift @@ -17,10 +17,10 @@ let package = Package( targets: ["MiddlewareRum"]), ], dependencies: [ - .package(url:"https://github.com/microsoft/plcrashreporter", from: "1.8.0"), + .package(url: "https://github.com/microsoft/plcrashreporter", from: "1.8.0"), .package(url: "https://github.com/devicekit/DeviceKit.git", from: "5.1.0"), .package(url: "https://github.com/tsolomko/SWCompression.git", .upToNextMajor(from: "4.8.5")), - .package(url: "https://github.com/apple/swift-protobuf.git", from: "1.27.0") + .package(url: "https://github.com/apple/swift-protobuf.git", from: "1.27.0"), ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. @@ -39,7 +39,7 @@ let package = Package( name: "MiddlewareRumTests", dependencies: [ "MiddlewareRum", - .product(name: "CrashReporter", package: "PLCrashReporter"), + .product(name: "CrashReporter", package: "PLCrashReporter") ]), ] ) diff --git a/README.md b/README.md index 70aa345..8c57737 100644 --- a/README.md +++ b/README.md @@ -31,13 +31,13 @@ ### Add the following line in `Package.swift` in `dependencies` ```swift -.package(url: "https://github.com/middleware-labs/middleware-ios", from: "1.0.5"), +.package(url: "https://github.com/middleware-labs/middleware-ios", from: "1.0.6"), ``` ## Using Cocoapods ```ruby -pod "MiddlewareRum", "~> 1.0.5" +pod "MiddlewareRum", "~> 1.0.6" ``` ## Initialization of Middleware iOS sdk diff --git a/Sources/MiddlewareRum/CrashReportingInstrumentation.swift b/Sources/MiddlewareRum/CrashReportingInstrumentation.swift index a21069e..f3291dd 100644 --- a/Sources/MiddlewareRum/CrashReportingInstrumentation.swift +++ b/Sources/MiddlewareRum/CrashReportingInstrumentation.swift @@ -90,22 +90,23 @@ class CrashReportingInstrumentation { } let now = Date() - let span = tracer().spanBuilder(spanName: exceptionType ?? "exception").setStartTime(time: now).startSpan() + + let span = tracer().spanBuilder(spanName: exceptionType!).setStartTime(time: now).startSpan() span.setAttribute(key: MiddlewareConstants.Attributes.COMPONENT, value: "crash") span.setAttribute(key: MiddlewareConstants.Attributes.EVENT_TYPE, value: "error") + if(report.customData != nil ) { let customData = try NSKeyedUnarchiver.unarchivedObject(ofClass: NSDictionary.self, from: report.customData) as? [String: String] if(customData != nil) { - span.setAttribute(key: "crash.rumSessionId", value: customData!["sessionId"]!) - span.setAttribute(key: "crash.batteryLevel", value: customData!["batteryLevel"]!) - span.setAttribute(key: "crash.freeDiskSpace", value: customData!["freeDiskSpace"]!) - span.setAttribute(key: "crash.freeMemory", value: customData!["freeMemory"]!) + span.setAttribute(key: MiddlewareConstants.Attributes.CRASH_SESSION_ID, value: customData!["sessionId"]!) + span.setAttribute(key: MiddlewareConstants.Attributes.CRASH_BATTERY_LEVEL, value: customData!["batteryLevel"]!) + span.setAttribute(key: MiddlewareConstants.Attributes.CRASH_FREE_DISK_SPACE, value: customData!["freeDiskSpace"]!) + span.setAttribute(key: MiddlewareConstants.Attributes.CRASH_FREE_MEMORY, value: customData!["freeMemory"]!) } else { - span.setAttribute(key: "crash.rumSessionId", value: String(decoding: report.customData, as: UTF8.self)) + span.setAttribute(key: MiddlewareConstants.Attributes.CRASH_SESSION_ID, value: String(decoding: report.customData, as: UTF8.self)) } } - span.setAttribute(key: "crash.app.version", value: report.applicationInfo.applicationMarketingVersion) - span.setAttribute(key: "error", value: true) + span.setAttribute(key: MiddlewareConstants.Attributes.CRASH_APP_VERSION, value: report.applicationInfo.applicationMarketingVersion) var exceptionAttributes = [String: AttributeValue]() #if !os(macOS) span.setAttribute(key: MiddlewareConstants.Attributes.DEVICE_MODEL_NAME, value: DeviceKit.Device.current.description) @@ -113,21 +114,25 @@ class CrashReportingInstrumentation { span.setAttribute(key: MiddlewareConstants.Attributes.DEVICE_MODEL_NAME, value: Device.current.model) #endif - exceptionAttributes["exception.type"] = AttributeValue(exceptionType ?? "unknown") - span.setAttribute(key: "crash.address", value: report.signalInfo.address.description) + exceptionAttributes[MiddlewareConstants.Attributes.EXCEPTION_TYPE] = AttributeValue(exceptionType!) + span.setAttribute(key: MiddlewareConstants.Attributes.CRASH_ADDRESS, value: report.signalInfo.address.description) for case let thread as PLCrashReportThreadInfo in report.threads where thread.crashed { - exceptionAttributes["exception.stacktrace"] = AttributeValue(crashedThreadToStack(report: report, thread: thread)) + exceptionAttributes[MiddlewareConstants.Attributes.EXCEPTION_STACKTRACE] = AttributeValue(crashedThreadToStack(report: report, thread: thread)) + exceptionAttributes[MiddlewareConstants.Attributes.ERROR_STACK] = exceptionAttributes[MiddlewareConstants.Attributes.EXCEPTION_STACKTRACE] break } if report.hasExceptionInfo { if(report.exceptionInfo.exceptionName != nil) { - exceptionAttributes["exception.type"] = AttributeValue(report.exceptionInfo.exceptionName as Any) + exceptionAttributes[MiddlewareConstants.Attributes.EXCEPTION_TYPE] = AttributeValue(report.exceptionInfo.exceptionName as Any) } if(report.exceptionInfo.exceptionReason != nil) { - exceptionAttributes["exception.message"] = AttributeValue(report.exceptionInfo.exceptionReason as Any) + exceptionAttributes[MiddlewareConstants.Attributes.EXCEPTION_MESSAGE] = AttributeValue(report.exceptionInfo.exceptionReason as Any) + exceptionAttributes[MiddlewareConstants.Attributes.ERROR_MESSAGE] = exceptionAttributes[MiddlewareConstants.Attributes.EXCEPTION_MESSAGE] } } - span.addEvent(name: "crash.timestamp", attributes: exceptionAttributes, timestamp: report.systemInfo.timestamp) + exceptionAttributes[MiddlewareConstants.Attributes.ERROR_TYPE] = exceptionAttributes[MiddlewareConstants.Attributes.EXCEPTION_TYPE] + + span.addEvent(name: MiddlewareConstants.Attributes.CRASH_TIMESTAMP, attributes: exceptionAttributes, timestamp: report.systemInfo.timestamp) span.end(time: now) } diff --git a/Sources/MiddlewareRum/GlobalAttributesProcessor.swift b/Sources/MiddlewareRum/GlobalAttributesProcessor.swift index 15df026..b12b064 100644 --- a/Sources/MiddlewareRum/GlobalAttributesProcessor.swift +++ b/Sources/MiddlewareRum/GlobalAttributesProcessor.swift @@ -39,6 +39,7 @@ class GlobalAttributesProcessor: SpanProcessor { span.setAttribute(key: MiddlewareConstants.Attributes.APP_VERSION, value: appVersion!) } span.setAttribute(key: MiddlewareConstants.Attributes.SESSION_ID, value: getRumSessionId()) + span.setAttribute(key: MiddlewareConstants.Attributes.SESSION_START_TIME, value: getSessionStartTime()) span.setAttribute(key: MiddlewareConstants.Attributes.RUM_SDK_VERSION, value: MiddlewareConstants.Global.VERSION_STRING) span.setAttribute(key: MiddlewareConstants.Attributes.DEVICE_MODEL_NAME, value: deviceModel) if Thread.current.isMainThread { diff --git a/Sources/MiddlewareRum/MiddlewareConstants.swift b/Sources/MiddlewareRum/MiddlewareConstants.swift index 05335d8..e5c00f0 100644 --- a/Sources/MiddlewareRum/MiddlewareConstants.swift +++ b/Sources/MiddlewareRum/MiddlewareConstants.swift @@ -4,6 +4,9 @@ import Foundation enum MiddlewareConstants { enum Global { + static let PROJECT_NAME = "project.name" + static let ACCOUNT_KEY = "mw.account_key" + static let MW_RUM = "mw.rum" static let INSTRUMENTATION_NAME = "middleware-ios" static let VERSION_STRING = "1.0.1" static let UNKNOWN_APP_NAME = "unknown-app" @@ -16,11 +19,22 @@ enum MiddlewareConstants { static let RUM_SDK_VERSION = "mw.rum.sdk.version" static let DEVICE_MODEL_NAME = "device.model.name" static let ERROR = "error" + static let ERROR_TYPE = "error.type" + static let ERROR_MESSAGE = "error.message" + static let ERROR_STACK = "error.stack" + static let CRASH_ADDRESS = "crash.address" + static let CRASH_APP_VERSION = "crash.app.version" + static let CRASH_SESSION_ID = "crash.rumSessionId" + static let CRASH_BATTERY_LEVEL = "crash.batteryLevel" + static let CRASH_FREE_DISK_SPACE = "crash.freeDiskSpace" + static let CRASH_FREE_MEMORY = "crash.freeMemory" + static let CRASH_TIMESTAMP = "crash.timestamp" static let COUNT = "count" static let EVENT_TYPE = "event.type" - static let OS_NAME = "os.name" + static let OS = "os" static let OS_VERSION = "os.version" static let SESSION_ID = "session.id" + static let SESSION_START_TIME = "session.start_time" static let PREVIOUS_SESSION_ID = "previous.session.id" static let EXCEPTION_MESSAGE = "exception.message" static let EXCEPTION_TYPE = "exception.type" diff --git a/Sources/MiddlewareRum/MiddlewareRum.swift b/Sources/MiddlewareRum/MiddlewareRum.swift index f481ddb..03a4fdc 100644 --- a/Sources/MiddlewareRum/MiddlewareRum.swift +++ b/Sources/MiddlewareRum/MiddlewareRum.swift @@ -182,13 +182,14 @@ public enum CheckState { class func createMiddlewareResource(builder: MiddlewareRumBuilder) -> Resource { var defaultResource = DefaultResources().get() defaultResource.merge(other: Resource(attributes: [ - "mw.account_key" :AttributeValue(builder.rumAccessToken!), + MiddlewareConstants.Global.ACCOUNT_KEY: AttributeValue(builder.rumAccessToken!), ResourceAttributes.serviceName.rawValue : AttributeValue(builder.serviceName!), - "browser.trace" : AttributeValue("true"), - "mw.rum" : AttributeValue("true"), + MiddlewareConstants.Global.MW_RUM : AttributeValue("true"), + MiddlewareConstants.Attributes.OS: AttributeValue("iOS"), ResourceAttributes.deviceModelName.rawValue: AttributeValue(Device.current.model), - "project.name":AttributeValue(builder.projectName!), - "session.id": AttributeValue(getSessionId()) + MiddlewareConstants.Global.PROJECT_NAME: AttributeValue(builder.projectName!), + MiddlewareConstants.Attributes.SESSION_ID: AttributeValue(getSessionId()), + MiddlewareConstants.Attributes.SESSION_START_TIME: AttributeValue(getSessionStartTime()), ])) return defaultResource } @@ -282,7 +283,7 @@ public enum CheckState { let now = Date() let typeName = e.name.rawValue let span = tracer.spanBuilder(spanName: typeName).setStartTime(time: now).startSpan() - span.setAttribute(key: MiddlewareConstants.Attributes.COMPONENT, value: "error") + span.setAttribute(key: MiddlewareConstants.Attributes.COMPONENT, value: "crash") span.setAttribute(key: MiddlewareConstants.Attributes.EVENT_TYPE, value: "error") span.setAttribute(key: MiddlewareConstants.Attributes.ERROR, value: true) span.setAttribute(key: MiddlewareConstants.Attributes.EXCEPTION_TYPE, value: typeName) @@ -308,7 +309,7 @@ public enum CheckState { let now = Date() let typeName = String(describing: type(of: e)) let span = tracer.spanBuilder(spanName: typeName).setStartTime(time: now).startSpan() - span.setAttribute(key: MiddlewareConstants.Attributes.COMPONENT, value: "error") + span.setAttribute(key: MiddlewareConstants.Attributes.COMPONENT, value: "crash") span.setAttribute(key: MiddlewareConstants.Attributes.EVENT_TYPE, value: "error") span.setAttribute(key: MiddlewareConstants.Attributes.ERROR, value: true) span.setAttribute(key: MiddlewareConstants.Attributes.EXCEPTION_TYPE, value: typeName) @@ -327,7 +328,7 @@ public enum CheckState { let now = Date() let typeName = "MiddlewareRum.addError(String)" let span = tracer.spanBuilder(spanName: typeName).setStartTime(time: now).startSpan() - span.setAttribute(key: MiddlewareConstants.Attributes.COMPONENT, value: "error") + span.setAttribute(key: MiddlewareConstants.Attributes.COMPONENT, value: "crash") span.setAttribute(key: MiddlewareConstants.Attributes.EVENT_TYPE, value: "error") span.setAttribute(key: MiddlewareConstants.Attributes.ERROR, value: true) span.setAttribute(key: MiddlewareConstants.Attributes.EXCEPTION_TYPE, value: "String") diff --git a/Sources/MiddlewareRum/Session.swift b/Sources/MiddlewareRum/Session.swift index 43da872..6059908 100644 --- a/Sources/MiddlewareRum/Session.swift +++ b/Sources/MiddlewareRum/Session.swift @@ -8,6 +8,7 @@ private var rumSessionId = generateNewSessionId() private var sessionIdExpiration = Date().addingTimeInterval(TimeInterval(MAX_SESSION_AGE_SECONDS)) private let sessionIdLock = NSLock() private var sessionIdCallbacks: [(() -> Void)] = [] +private var sessionStartTime = Int(Date().timeIntervalSince1970 * 1000) func generateNewSessionId() -> String { var i=0 @@ -43,6 +44,7 @@ func getRumSessionId(forceNewSessionId: Bool = false) -> String { sessionIdExpiration = Date().addingTimeInterval(TimeInterval(MAX_SESSION_AGE_SECONDS)) oldRumSessionId = rumSessionId rumSessionId = generateNewSessionId() + sessionStartTime = Int(Date().timeIntervalSince1970 * 1000) isSessionIdChanged = true callbacks = sessionIdCallbacks } @@ -52,17 +54,23 @@ func getRumSessionId(forceNewSessionId: Bool = false) -> String { callback() } if isSessionIdChanged { - createSessionIdChangeSpan(newSessionId: rumSessionId, previousSessionId: oldRumSessionId) + createSessionIdChangeSpan(newSessionId: rumSessionId, previousSessionId: oldRumSessionId, sessionStartTime: sessionStartTime) } return rumSessionId } -func createSessionIdChangeSpan(newSessionId: String, previousSessionId: String) { + +func getSessionStartTime() -> Int { + return sessionStartTime +} + +func createSessionIdChangeSpan(newSessionId: String, previousSessionId: String, sessionStartTime: Int) { let now = Date() let tracer = OpenTelemetry.instance.tracerProvider.get( instrumentationName: MiddlewareConstants.Global.INSTRUMENTATION_NAME, instrumentationVersion: MiddlewareConstants.Global.VERSION_STRING) var activeResource = OpenTelemetry.instance.tracerProvider.getActiveResource() activeResource.attributes[MiddlewareConstants.Attributes.SESSION_ID] = AttributeValue(newSessionId) + activeResource.attributes[MiddlewareConstants.Attributes.SESSION_START_TIME] = AttributeValue(sessionStartTime) OpenTelemetry.instance.tracerProvider.updateActiveResource(activeResource) let span = tracer.spanBuilder(spanName: MiddlewareConstants.Spans.SESSION_ID_CHANGE).setStartTime(time: now).startSpan()