From 9baf117bad1ca8f9e0aa5d1df7a7b88e8eb76f48 Mon Sep 17 00:00:00 2001 From: Jamie Lynch Date: Mon, 13 Jan 2025 11:11:15 +0000 Subject: [PATCH] refactor: alter log service implementation --- .../internal/injection/LogModuleImpl.kt | 3 +- .../internal/logs/EmbraceLogService.kt | 66 +++-------- .../embracesdk/internal/logs/LogService.kt | 16 +-- .../internal/logs/EmbraceLogServiceTest.kt | 90 --------------- .../embrace/android/embracesdk/EmbraceImpl.kt | 33 +++--- .../delegate/EmbraceInternalInterfaceImpl.kt | 13 +-- .../delegate/FlutterInternalInterfaceImpl.kt | 24 ++-- .../internal/api/delegate/LogsApiDelegate.kt | 104 ++++++++---------- .../ReactNativeInternalInterfaceImpl.kt | 13 +-- .../delegate/UnityInternalInterfaceImpl.kt | 16 +-- .../api/EmbraceInternalInterfaceImplTest.kt | 23 ---- .../api/FlutterInternalInterfaceImplTest.kt | 31 +++--- .../api/UnityInternalInterfaceImplTest.kt | 32 ++---- .../api/delegate/LogsApiDelegateTest.kt | 7 +- .../embracesdk/fakes/FakeLogService.kt | 24 +--- .../fakes/injection/FakeLogModule.kt | 4 +- 16 files changed, 140 insertions(+), 359 deletions(-) diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/LogModuleImpl.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/LogModuleImpl.kt index 21fb7d63c9..6dfe51efdf 100644 --- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/LogModuleImpl.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/LogModuleImpl.kt @@ -61,8 +61,7 @@ internal class LogModuleImpl( EmbraceLogService( essentialServiceModule.logWriter, configModule.configService, - essentialServiceModule.sessionPropertiesService, - initModule.jsonSerializer + essentialServiceModule.sessionPropertiesService ) } diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/logs/EmbraceLogService.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/logs/EmbraceLogService.kt index 5b36c8629e..6dfe02e372 100644 --- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/logs/EmbraceLogService.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/logs/EmbraceLogService.kt @@ -3,8 +3,6 @@ package io.embrace.android.embracesdk.internal.logs import io.embrace.android.embracesdk.LogExceptionType import io.embrace.android.embracesdk.Severity import io.embrace.android.embracesdk.internal.arch.destination.LogWriter -import io.embrace.android.embracesdk.internal.arch.schema.EmbType.System.FlutterException.embFlutterExceptionContext -import io.embrace.android.embracesdk.internal.arch.schema.EmbType.System.FlutterException.embFlutterExceptionLibrary import io.embrace.android.embracesdk.internal.arch.schema.SchemaType import io.embrace.android.embracesdk.internal.arch.schema.SchemaType.Exception import io.embrace.android.embracesdk.internal.arch.schema.SchemaType.FlutterException @@ -15,11 +13,10 @@ import io.embrace.android.embracesdk.internal.config.ConfigService import io.embrace.android.embracesdk.internal.config.behavior.REDACTED_LABEL import io.embrace.android.embracesdk.internal.opentelemetry.embExceptionHandling import io.embrace.android.embracesdk.internal.payload.AppFramework -import io.embrace.android.embracesdk.internal.serialization.PlatformSerializer -import io.embrace.android.embracesdk.internal.serialization.truncatedStacktrace import io.embrace.android.embracesdk.internal.spans.toOtelSeverity +import io.embrace.android.embracesdk.internal.utils.PropertyUtils.normalizeProperties import io.embrace.android.embracesdk.internal.utils.Uuid -import io.opentelemetry.semconv.ExceptionAttributes +import io.opentelemetry.api.common.AttributeKey import io.opentelemetry.semconv.incubating.LogIncubatingAttributes /** @@ -29,7 +26,6 @@ class EmbraceLogService( private val logWriter: LogWriter, private val configService: ConfigService, private val sessionPropertiesService: SessionPropertiesService, - private val serializer: PlatformSerializer, ) : LogService { private val behavior = configService.logMessageBehavior @@ -44,38 +40,18 @@ class EmbraceLogService( severity: Severity, logExceptionType: LogExceptionType, properties: Map?, - stackTraceElements: Array?, - customStackTrace: String?, - context: String?, - library: String?, - exceptionName: String?, - exceptionMessage: String?, + customLogAttrs: Map, String>, ) { - val redactedProperties = redactSensitiveProperties(properties) - val attrs = createTelemetryAttributes(redactedProperties) + val redactedProperties = redactSensitiveProperties(normalizeProperties(properties)) + val attrs = createTelemetryAttributes(redactedProperties, customLogAttrs) val schemaProvider: (TelemetryAttributes) -> SchemaType = when { logExceptionType == LogExceptionType.NONE -> ::Log configService.appFramework == AppFramework.FLUTTER -> ::FlutterException else -> ::Exception } - if (logExceptionType != LogExceptionType.NONE) { - val stacktrace = stackTraceElements?.let(serializer::truncatedStacktrace) ?: customStackTrace - populateLogExceptionAttributes( - attributes = attrs, - logExceptionType = logExceptionType, - stackTrace = stacktrace, - type = exceptionName, - message = exceptionMessage, - ) - if (configService.appFramework == AppFramework.FLUTTER) { - populateFlutterExceptionAttrs( - context = context, - library = library, - attrs = attrs - ) - } + attrs.setAttribute(embExceptionHandling, logExceptionType.value) } addLogEventData( message = message, @@ -85,15 +61,6 @@ class EmbraceLogService( ) } - private fun populateFlutterExceptionAttrs( - context: String?, - library: String?, - attrs: TelemetryAttributes, - ) { - context?.let { attrs.setAttribute(embFlutterExceptionContext, it) } - library?.let { attrs.setAttribute(embFlutterExceptionLibrary, it) } - } - override fun getErrorLogsCount(): Int { return logCounters.getValue(Severity.ERROR).getCount() } @@ -105,29 +72,22 @@ class EmbraceLogService( /** * Create [TelemetryAttributes] with the standard log properties */ - private fun createTelemetryAttributes(customProperties: Map?): TelemetryAttributes { + private fun createTelemetryAttributes( + customProperties: Map?, + logAttrs: Map, String>, + ): TelemetryAttributes { val attributes = TelemetryAttributes( configService = configService, sessionPropertiesProvider = sessionPropertiesService::getProperties, customAttributes = customProperties?.mapValues { it.value.toString() } ?: emptyMap() ) attributes.setAttribute(LogIncubatingAttributes.LOG_RECORD_UID, Uuid.getEmbUuid()) + logAttrs.forEach { + attributes.setAttribute(it.key, it.value) + } return attributes } - private fun populateLogExceptionAttributes( - attributes: TelemetryAttributes, - logExceptionType: LogExceptionType, - stackTrace: String?, - type: String?, - message: String?, - ) { - attributes.setAttribute(embExceptionHandling, logExceptionType.value) - type?.let { attributes.setAttribute(ExceptionAttributes.EXCEPTION_TYPE, it) } - message?.let { attributes.setAttribute(ExceptionAttributes.EXCEPTION_MESSAGE, it) } - stackTrace?.let { attributes.setAttribute(ExceptionAttributes.EXCEPTION_STACKTRACE, it) } - } - private fun addLogEventData( message: String, severity: Severity, diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/logs/LogService.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/logs/LogService.kt index 7289c4eab9..d5934a7249 100644 --- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/logs/LogService.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/logs/LogService.kt @@ -3,6 +3,7 @@ package io.embrace.android.embracesdk.internal.logs import io.embrace.android.embracesdk.LogExceptionType import io.embrace.android.embracesdk.Severity import io.embrace.android.embracesdk.internal.session.MemoryCleanerListener +import io.opentelemetry.api.common.AttributeKey /** * Creates log records to be sent using the Open Telemetry Logs data model. @@ -13,15 +14,9 @@ interface LogService : MemoryCleanerListener { * Creates a remote log. * * @param message the message to log - * @param type the type of message to log, which must be INFO_LOG, WARNING_LOG, or ERROR_LOG + * @param severity the log severity * @param logExceptionType whether the log is a handled exception, unhandled, or non an exception * @param properties custom properties to send as part of the event - * @param stackTraceElements the stacktrace elements of a throwable - * @param customStackTrace stacktrace string for non-JVM exceptions - * @param context the context of the exception - * @param library the library of the exception - * @param exceptionName the exception name of a Throwable is it is present - * @param exceptionMessage the exception message of a Throwable is it is present */ @Suppress("LongParameterList") fun log( @@ -29,12 +24,7 @@ interface LogService : MemoryCleanerListener { severity: Severity, logExceptionType: LogExceptionType, properties: Map? = null, - stackTraceElements: Array? = null, - customStackTrace: String? = null, - context: String? = null, - library: String? = null, - exceptionName: String? = null, - exceptionMessage: String? = null, + customLogAttrs: Map, String> = emptyMap(), ) /** diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/logs/EmbraceLogServiceTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/logs/EmbraceLogServiceTest.kt index 428f8ab5a0..1680bda5f1 100644 --- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/logs/EmbraceLogServiceTest.kt +++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/logs/EmbraceLogServiceTest.kt @@ -2,7 +2,6 @@ package io.embrace.android.embracesdk.internal.logs import io.embrace.android.embracesdk.LogExceptionType import io.embrace.android.embracesdk.Severity -import io.embrace.android.embracesdk.arch.assertIsType import io.embrace.android.embracesdk.fakes.FakeConfigService import io.embrace.android.embracesdk.fakes.FakeLogWriter import io.embrace.android.embracesdk.fakes.FakeSessionPropertiesService @@ -10,18 +9,13 @@ import io.embrace.android.embracesdk.fakes.behavior.FakeLogMessageBehavior import io.embrace.android.embracesdk.fakes.config.FakeInstrumentedConfig import io.embrace.android.embracesdk.fakes.config.FakeRedactionConfig import io.embrace.android.embracesdk.fakes.createSessionBehavior -import io.embrace.android.embracesdk.internal.arch.schema.EmbType import io.embrace.android.embracesdk.internal.arch.schema.toSessionPropertyAttributeName import io.embrace.android.embracesdk.internal.config.behavior.REDACTED_LABEL import io.embrace.android.embracesdk.internal.config.behavior.SensitiveKeysBehaviorImpl import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig import io.embrace.android.embracesdk.internal.config.remote.SessionRemoteConfig -import io.embrace.android.embracesdk.internal.opentelemetry.embExceptionHandling import io.embrace.android.embracesdk.internal.payload.AppFramework -import io.embrace.android.embracesdk.internal.serialization.EmbraceSerializer -import io.opentelemetry.semconv.ExceptionAttributes import io.opentelemetry.semconv.incubating.LogIncubatingAttributes -import org.junit.Assert import org.junit.Assert.assertEquals import org.junit.Assert.assertNotEquals import org.junit.Assert.assertTrue @@ -35,8 +29,6 @@ internal class EmbraceLogServiceTest { private lateinit var fakeSessionPropertiesService: FakeSessionPropertiesService private lateinit var fakeConfigService: FakeConfigService - private val embraceSerializer = EmbraceSerializer() - @Before fun setUp() { fakeConfigService = FakeConfigService( @@ -54,7 +46,6 @@ internal class EmbraceLogServiceTest { logWriter = fakeLogWriter, configService = fakeConfigService, sessionPropertiesService = fakeSessionPropertiesService, - serializer = embraceSerializer, ) @Test @@ -246,85 +237,4 @@ internal class EmbraceLogServiceTest { // then the correct number of error logs is returned assertEquals(5, logService.getErrorLogsCount()) } - - @Test - fun `stacktrace elements are truncated`() { - // given a stacktrace with more than 200 elements - val stackTrace = Array(201) { StackTraceElement("TestClass", "testMethod", "testFile", it) } - - // when logging a message with the stacktrace - logService.log("message", Severity.INFO, LogExceptionType.HANDLED, stackTraceElements = stackTrace) - - // then the stacktrace is truncated - val log = fakeLogWriter.logEvents.single() - val truncatedStacktraceString = log.schemaType.attributes()[ExceptionAttributes.EXCEPTION_STACKTRACE.key] ?: "" - - // serialize back to Array to get the size - val truncatedStacktrace = embraceSerializer.fromJson(truncatedStacktraceString, List::class.java) - assertEquals(200, truncatedStacktrace.size) - } - - @Test - fun `exception is logged`() { - // given an exception - val message = "Oh no" - val exception = NullPointerException("Oh no!") - - // when logging it - logService.log( - message = message, - severity = Severity.WARNING, - logExceptionType = LogExceptionType.HANDLED, - stackTraceElements = exception.stackTrace, - exceptionName = exception.javaClass.simpleName, - exceptionMessage = exception.message, - ) - - // then the exception is correctly logged - val log = fakeLogWriter.logEvents.single() - assertEquals(message, log.message) - assertEquals(io.opentelemetry.api.logs.Severity.WARN, log.severity) - val attributes = log.schemaType.attributes() - Assert.assertNotNull(attributes[LogIncubatingAttributes.LOG_RECORD_UID.key]) - assertEquals(LogExceptionType.HANDLED.value, attributes[embExceptionHandling.name]) - assertEquals(exception.javaClass.simpleName, attributes[ExceptionAttributes.EXCEPTION_TYPE.key]) - assertEquals(exception.message, attributes[ExceptionAttributes.EXCEPTION_MESSAGE.key]) - log.assertIsType(EmbType.System.Exception) - } - - @Test - fun `flutter exception is logged`() { - // given a flutter exception - val flutterMessage = "Dart error" - val flutterContext = "Flutter context" - val flutterLibrary = "Flutter library" - val flutterException = NullPointerException("Something broke on Flutter") - fakeConfigService = FakeConfigService(appFramework = AppFramework.FLUTTER) - logService = createEmbraceLogService() - - // when logging it - logService.log( - message = flutterMessage, - severity = Severity.ERROR, - logExceptionType = LogExceptionType.HANDLED, - stackTraceElements = flutterException.stackTrace, - exceptionName = flutterException.javaClass.simpleName, - exceptionMessage = flutterException.message, - context = flutterContext, - library = flutterLibrary - ) - - // then the exception is correctly logged - val log = fakeLogWriter.logEvents.single() - assertEquals(flutterMessage, log.message) - assertEquals(io.opentelemetry.api.logs.Severity.ERROR, log.severity) - val attributes = log.schemaType.attributes() - Assert.assertNotNull(attributes[LogIncubatingAttributes.LOG_RECORD_UID.key]) - assertEquals(LogExceptionType.HANDLED.value, attributes[embExceptionHandling.name]) - assertEquals(flutterException.javaClass.simpleName, attributes[ExceptionAttributes.EXCEPTION_TYPE.key]) - assertEquals(flutterException.message, attributes[ExceptionAttributes.EXCEPTION_MESSAGE.key]) - assertEquals(flutterContext, attributes[EmbType.System.FlutterException.embFlutterExceptionContext.name]) - assertEquals(flutterLibrary, attributes[EmbType.System.FlutterException.embFlutterExceptionLibrary.name]) - log.assertIsType(EmbType.System.FlutterException) - } } diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/EmbraceImpl.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/EmbraceImpl.kt index 0ca46f7a5d..aaff31da05 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/EmbraceImpl.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/EmbraceImpl.kt @@ -48,6 +48,7 @@ import io.embrace.android.embracesdk.internal.payload.AppFramework import io.embrace.android.embracesdk.internal.worker.TaskPriority import io.embrace.android.embracesdk.internal.worker.Worker import io.embrace.android.embracesdk.spans.TracingApi +import io.opentelemetry.api.common.AttributeKey import java.util.concurrent.Executors import java.util.concurrent.atomic.AtomicBoolean @@ -296,26 +297,24 @@ internal class EmbraceImpl @JvmOverloads constructor( fun logMessage( severity: Severity, message: String, - properties: Map?, - stackTraceElements: Array?, - customStackTrace: String?, - logExceptionType: LogExceptionType, - context: String?, - library: String?, + properties: Map? = null, + stackTraceElements: Array? = null, + customStackTrace: String? = null, + logExceptionType: LogExceptionType = LogExceptionType.NONE, exceptionName: String? = null, exceptionMessage: String? = null, + customLogAttrs: Map, String> = emptyMap(), ) { - logsApiDelegate.logMessage( - severity, - message, - properties, - stackTraceElements, - customStackTrace, - logExceptionType, - context, - library, - exceptionName, - exceptionMessage + logsApiDelegate.logMessageImpl( + severity = severity, + message = message, + properties = properties, + stackTraceElements = stackTraceElements, + customStackTrace = customStackTrace, + logExceptionType = logExceptionType, + exceptionName = exceptionName, + exceptionMessage = exceptionMessage, + customLogAttrs = customLogAttrs ) } diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/api/delegate/EmbraceInternalInterfaceImpl.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/api/delegate/EmbraceInternalInterfaceImpl.kt index 1309a37efd..bf1776dac0 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/api/delegate/EmbraceInternalInterfaceImpl.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/api/delegate/EmbraceInternalInterfaceImpl.kt @@ -4,7 +4,6 @@ package io.embrace.android.embracesdk.internal.api.delegate import android.annotation.SuppressLint import io.embrace.android.embracesdk.EmbraceImpl -import io.embrace.android.embracesdk.LogExceptionType import io.embrace.android.embracesdk.LogType import io.embrace.android.embracesdk.Severity import io.embrace.android.embracesdk.internal.EmbraceInternalInterface @@ -61,14 +60,10 @@ internal class EmbraceInternalInterfaceImpl( else -> Severity.INFO } embraceImpl.logMessage( - eventType, - throwable.message ?: "", - properties, - customStackTrace ?: throwable.stackTrace, - null, - LogExceptionType.NONE, - null, - null + severity = eventType, + message = throwable.message ?: "", + properties = properties, + stackTraceElements = customStackTrace ?: throwable.stackTrace, ) } diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/api/delegate/FlutterInternalInterfaceImpl.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/api/delegate/FlutterInternalInterfaceImpl.kt index 04b40deaf1..5265f36bce 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/api/delegate/FlutterInternalInterfaceImpl.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/api/delegate/FlutterInternalInterfaceImpl.kt @@ -5,8 +5,11 @@ import io.embrace.android.embracesdk.LogExceptionType import io.embrace.android.embracesdk.Severity import io.embrace.android.embracesdk.internal.EmbraceInternalInterface import io.embrace.android.embracesdk.internal.FlutterInternalInterface +import io.embrace.android.embracesdk.internal.arch.schema.EmbType.System.FlutterException.embFlutterExceptionContext +import io.embrace.android.embracesdk.internal.arch.schema.EmbType.System.FlutterException.embFlutterExceptionLibrary import io.embrace.android.embracesdk.internal.envelope.metadata.HostedSdkVersionInfo import io.embrace.android.embracesdk.internal.logging.EmbLogger +import io.opentelemetry.api.common.AttributeKey internal class FlutterInternalInterfaceImpl( private val embrace: EmbraceImpl, @@ -64,17 +67,18 @@ internal class FlutterInternalInterfaceImpl( exceptionType: LogExceptionType, ) { if (embrace.isStarted) { + val attrs = mutableMapOf, String>() + context?.let { attrs[embFlutterExceptionContext.attributeKey] = it } + library?.let { attrs[embFlutterExceptionLibrary.attributeKey] = it } + embrace.logMessage( - Severity.ERROR, - "Dart error", - null, - null, - stack, - exceptionType, - context, - library, - name, - message + severity = Severity.ERROR, + message = "Dart error", + customStackTrace = stack, + logExceptionType = exceptionType, + exceptionName = name, + exceptionMessage = message, + customLogAttrs = attrs ) } else { logger.logSdkNotInitialized("logDartError") diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/api/delegate/LogsApiDelegate.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/api/delegate/LogsApiDelegate.kt index a79bf41f6c..7d55ce164a 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/api/delegate/LogsApiDelegate.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/api/delegate/LogsApiDelegate.kt @@ -6,8 +6,10 @@ import io.embrace.android.embracesdk.internal.api.LogsApi import io.embrace.android.embracesdk.internal.injection.ModuleInitBootstrapper import io.embrace.android.embracesdk.internal.injection.embraceImplInject import io.embrace.android.embracesdk.internal.payload.PushNotificationBreadcrumb -import io.embrace.android.embracesdk.internal.utils.PropertyUtils.normalizeProperties +import io.embrace.android.embracesdk.internal.serialization.truncatedStacktrace import io.embrace.android.embracesdk.internal.utils.getSafeStackTrace +import io.opentelemetry.api.common.AttributeKey +import io.opentelemetry.semconv.ExceptionAttributes internal class LogsApiDelegate( bootstrapper: ModuleInitBootstrapper, @@ -21,18 +23,13 @@ internal class LogsApiDelegate( private val pushNotificationDataSource by embraceImplInject(sdkCallChecker) { bootstrapper.featureModule.pushNotificationDataSource.dataSource } - - override fun logInfo(message: String) { - logMessage(message, Severity.INFO) - } - - override fun logWarning(message: String) { - logMessage(message, Severity.WARNING) + private val serializer by embraceImplInject(sdkCallChecker) { + bootstrapper.initModule.jsonSerializer } - override fun logError(message: String) { - logMessage(message, Severity.ERROR) - } + override fun logInfo(message: String) = logMessage(message, Severity.INFO) + override fun logWarning(message: String) = logMessage(message, Severity.WARNING) + override fun logError(message: String) = logMessage(message, Severity.ERROR) override fun logMessage(message: String, severity: Severity) { logMessage(message, severity, null) @@ -75,15 +72,10 @@ internal class LogsApiDelegate( severity: Severity, properties: Map?, ) { - logMessage( - severity, - message, - properties, - null, - null, - LogExceptionType.NONE, - null, - null + logMessageImpl( + severity = severity, + message = message, + properties = properties, ) } @@ -93,21 +85,15 @@ internal class LogsApiDelegate( properties: Map?, message: String?, ) { - val exceptionMessage = if (throwable.message != null) throwable.message else "" - logMessage( - severity, - ( - message - ?: exceptionMessage - ) ?: "", - properties, - throwable.getSafeStackTrace(), - null, - LogExceptionType.HANDLED, - null, - null, - throwable.javaClass.simpleName, - exceptionMessage + val exceptionMessage = throwable.message ?: "" + logMessageImpl( + severity = severity, + message = message ?: exceptionMessage, + properties = properties, + stackTraceElements = throwable.getSafeStackTrace(), + logExceptionType = LogExceptionType.HANDLED, + exceptionName = throwable.javaClass.simpleName, + exceptionMessage = exceptionMessage ) } @@ -117,47 +103,43 @@ internal class LogsApiDelegate( properties: Map?, message: String?, ) { - logMessage( - severity, - message - ?: "", - properties, - stacktraceElements, - null, - LogExceptionType.HANDLED, - null, - null, - null, - message + logMessageImpl( + severity = severity, + message = message ?: "", + properties = properties, + stackTraceElements = stacktraceElements, + logExceptionType = LogExceptionType.HANDLED, + exceptionMessage = message ) } @JvmOverloads - fun logMessage( + fun logMessageImpl( severity: Severity, message: String, - properties: Map?, - stackTraceElements: Array?, - customStackTrace: String?, - logExceptionType: LogExceptionType, - context: String?, - library: String?, + properties: Map? = null, + stackTraceElements: Array? = null, + customStackTrace: String? = null, + logExceptionType: LogExceptionType = LogExceptionType.NONE, exceptionName: String? = null, exceptionMessage: String? = null, + customLogAttrs: Map, String> = emptyMap(), ) { if (sdkCallChecker.check("log_message")) { runCatching { + val attrs = mutableMapOf, String>() + exceptionName?.let { attrs[ExceptionAttributes.EXCEPTION_TYPE] = it } + exceptionMessage?.let { attrs[ExceptionAttributes.EXCEPTION_MESSAGE] = it } + + val stacktrace = stackTraceElements?.let(checkNotNull(serializer)::truncatedStacktrace) ?: customStackTrace + stacktrace?.let { attrs[ExceptionAttributes.EXCEPTION_STACKTRACE] = it } + logService?.log( message, severity, logExceptionType, - normalizeProperties(properties), - stackTraceElements, - customStackTrace, - context, - library, - exceptionName, - exceptionMessage + properties, + attrs.plus(customLogAttrs) ) sessionOrchestrator?.reportBackgroundActivityStateChange() } diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/api/delegate/ReactNativeInternalInterfaceImpl.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/api/delegate/ReactNativeInternalInterfaceImpl.kt index 233f2ce8ba..3e8e96396d 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/api/delegate/ReactNativeInternalInterfaceImpl.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/api/delegate/ReactNativeInternalInterfaceImpl.kt @@ -43,14 +43,11 @@ internal class ReactNativeInternalInterfaceImpl( ) { if (embrace.isStarted) { embrace.logMessage( - Severity.ERROR, - message, - properties, - null, - stacktrace, - LogExceptionType.HANDLED, - null, - null + severity = Severity.ERROR, + message = message, + properties = properties, + customStackTrace = stacktrace, + logExceptionType = LogExceptionType.HANDLED ) } else { logger.logSdkNotInitialized("log JS exception") diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/api/delegate/UnityInternalInterfaceImpl.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/api/delegate/UnityInternalInterfaceImpl.kt index cfd3586c6b..06c82e1aa1 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/api/delegate/UnityInternalInterfaceImpl.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/api/delegate/UnityInternalInterfaceImpl.kt @@ -58,16 +58,12 @@ internal class UnityInternalInterfaceImpl( ) { if (embrace.isStarted) { embrace.logMessage( - Severity.ERROR, - "Unity exception", - null, - null, - stacktrace, - exceptionType, - null, - null, - name, - message + severity = Severity.ERROR, + message = "Unity exception", + customStackTrace = stacktrace, + logExceptionType = exceptionType, + exceptionName = name, + exceptionMessage = message ) } else { logger.logSdkNotInitialized("log Unity exception") diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/internal/api/EmbraceInternalInterfaceImplTest.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/internal/api/EmbraceInternalInterfaceImplTest.kt index 14095f9cf4..a37d110d74 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/internal/api/EmbraceInternalInterfaceImplTest.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/internal/api/EmbraceInternalInterfaceImplTest.kt @@ -1,12 +1,8 @@ -@file:Suppress("DEPRECATION") - package io.embrace.android.embracesdk.internal.api import android.net.Uri import android.webkit.URLUtil import io.embrace.android.embracesdk.EmbraceImpl -import io.embrace.android.embracesdk.LogExceptionType -import io.embrace.android.embracesdk.LogType import io.embrace.android.embracesdk.Severity import io.embrace.android.embracesdk.fakes.FakeClock import io.embrace.android.embracesdk.fakes.FakeConfigService @@ -81,25 +77,6 @@ internal class EmbraceInternalInterfaceImplTest { } } - @Suppress("DEPRECATION") - @Test - fun testLogHandledException() { - val exception = Throwable("handled exception") - internalImpl.logHandledException(exception, LogType.ERROR, emptyMap(), null) - verify(exactly = 1) { - embraceImpl.logMessage( - Severity.ERROR, - "handled exception", - emptyMap(), - exception.stackTrace, - null, - LogExceptionType.NONE, - null, - null - ) - } - } - @Test fun testCompletedNetworkRequest() { mockkStatic(Uri::class) diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/internal/api/FlutterInternalInterfaceImplTest.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/internal/api/FlutterInternalInterfaceImplTest.kt index f27b30f1c3..3fa1612c05 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/internal/api/FlutterInternalInterfaceImplTest.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/internal/api/FlutterInternalInterfaceImplTest.kt @@ -5,6 +5,8 @@ import io.embrace.android.embracesdk.LogExceptionType import io.embrace.android.embracesdk.Severity import io.embrace.android.embracesdk.fakes.FakePreferenceService import io.embrace.android.embracesdk.internal.api.delegate.FlutterInternalInterfaceImpl +import io.embrace.android.embracesdk.internal.arch.schema.EmbType.System.FlutterException.embFlutterExceptionContext +import io.embrace.android.embracesdk.internal.arch.schema.EmbType.System.FlutterException.embFlutterExceptionLibrary import io.embrace.android.embracesdk.internal.envelope.metadata.HostedSdkVersionInfo import io.embrace.android.embracesdk.internal.logging.EmbLogger import io.embrace.android.embracesdk.internal.payload.AppFramework @@ -67,10 +69,12 @@ internal class FlutterInternalInterfaceImplTest { null, "stack", LogExceptionType.UNHANDLED, - "ctx", - "lib", "exception name", - "message" + "message", + mapOf( + embFlutterExceptionContext.attributeKey to "ctx", + embFlutterExceptionLibrary.attributeKey to "lib" + ), ) } } @@ -79,18 +83,19 @@ internal class FlutterInternalInterfaceImplTest { fun testLogHandledDartException() { every { embrace.isStarted } returns true impl.logHandledDartException("stack", "exception name", "message", "ctx", "lib") + verify(exactly = 1) { embrace.logMessage( - Severity.ERROR, - "Dart error", - null, - null, - "stack", - LogExceptionType.HANDLED, - "ctx", - "lib", - "exception name", - "message" + severity = Severity.ERROR, + message = "Dart error", + customStackTrace = "stack", + logExceptionType = LogExceptionType.HANDLED, + exceptionName = "exception name", + exceptionMessage = "message", + customLogAttrs = mapOf( + embFlutterExceptionContext.attributeKey to "ctx", + embFlutterExceptionLibrary.attributeKey to "lib" + ), ) } } diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/internal/api/UnityInternalInterfaceImplTest.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/internal/api/UnityInternalInterfaceImplTest.kt index 5b768238e2..ea65230d63 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/internal/api/UnityInternalInterfaceImplTest.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/internal/api/UnityInternalInterfaceImplTest.kt @@ -60,16 +60,12 @@ internal class UnityInternalInterfaceImplTest { impl.logUnhandledUnityException("name", "msg", "stack") verify(exactly = 1) { embrace.logMessage( - Severity.ERROR, - "Unity exception", - null, - null, - "stack", - LogExceptionType.UNHANDLED, - null, - null, - "name", - "msg" + severity = Severity.ERROR, + message = "Unity exception", + customStackTrace = "stack", + logExceptionType = LogExceptionType.UNHANDLED, + exceptionName = "name", + exceptionMessage = "msg" ) } } @@ -80,16 +76,12 @@ internal class UnityInternalInterfaceImplTest { impl.logHandledUnityException("name", "msg", "stack") verify(exactly = 1) { embrace.logMessage( - Severity.ERROR, - "Unity exception", - null, - null, - "stack", - LogExceptionType.HANDLED, - null, - null, - "name", - "msg" + severity = Severity.ERROR, + message = "Unity exception", + customStackTrace = "stack", + logExceptionType = LogExceptionType.HANDLED, + exceptionName = "name", + exceptionMessage = "msg" ) } } diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/internal/api/delegate/LogsApiDelegateTest.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/internal/api/delegate/LogsApiDelegateTest.kt index e38fbdfc16..a82e904f3b 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/internal/api/delegate/LogsApiDelegateTest.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/internal/api/delegate/LogsApiDelegateTest.kt @@ -11,7 +11,6 @@ import io.embrace.android.embracesdk.fakes.FakeTelemetryService import io.embrace.android.embracesdk.fakes.fakeModuleInitBootstrapper import io.embrace.android.embracesdk.fakes.injection.FakeLogModule import io.embrace.android.embracesdk.internal.payload.AppFramework -import org.junit.Assert.assertArrayEquals import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test @@ -67,7 +66,7 @@ internal class LogsApiDelegateTest { @Test fun logMessage() { - delegate.logMessage("test", Severity.WARNING) + delegate.logMessageImpl(message = "test", severity = Severity.WARNING) val log = logService.loggedMessages.single() assertEquals("test", log.message) assertEquals(Severity.WARNING, log.severity) @@ -122,7 +121,6 @@ internal class LogsApiDelegateTest { assertEquals("", log.message) assertEquals(Severity.ERROR, log.severity) assertEquals(LogExceptionType.HANDLED, log.logExceptionType) - assertArrayEquals(stacktrace, log.stackTraceElements) } @Test @@ -133,7 +131,6 @@ internal class LogsApiDelegateTest { assertEquals("", log.message) assertEquals(Severity.INFO, log.severity) assertEquals(LogExceptionType.HANDLED, log.logExceptionType) - assertArrayEquals(stacktrace, log.stackTraceElements) } @Test @@ -146,7 +143,6 @@ internal class LogsApiDelegateTest { assertEquals("", log.message) assertEquals(Severity.INFO, log.severity) assertEquals(LogExceptionType.HANDLED, log.logExceptionType) - assertArrayEquals(stacktrace, log.stackTraceElements) assertEquals(props, log.properties) } @@ -160,7 +156,6 @@ internal class LogsApiDelegateTest { assertEquals("my message", log.message) assertEquals(Severity.INFO, log.severity) assertEquals(LogExceptionType.HANDLED, log.logExceptionType) - assertArrayEquals(stacktrace, log.stackTraceElements) assertEquals(props, log.properties) } } diff --git a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeLogService.kt b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeLogService.kt index 1a9deb8440..f127be26fc 100644 --- a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeLogService.kt +++ b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeLogService.kt @@ -3,6 +3,7 @@ package io.embrace.android.embracesdk.fakes import io.embrace.android.embracesdk.LogExceptionType import io.embrace.android.embracesdk.Severity import io.embrace.android.embracesdk.internal.logs.LogService +import io.opentelemetry.api.common.AttributeKey class FakeLogService : LogService { class LogData( @@ -10,12 +11,6 @@ class FakeLogService : LogService { val severity: Severity, val logExceptionType: LogExceptionType, val properties: Map?, - val stackTraceElements: Array?, - val customStackTrace: String?, - val context: String?, - val library: String?, - val exceptionName: String?, - val exceptionMessage: String?, ) val logs: MutableList = mutableListOf() @@ -27,12 +22,7 @@ class FakeLogService : LogService { severity: Severity, logExceptionType: LogExceptionType, properties: Map?, - stackTraceElements: Array?, - customStackTrace: String?, - context: String?, - library: String?, - exceptionName: String?, - exceptionMessage: String?, + customLogAttrs: Map, String>, ) { loggedMessages.add( LogData( @@ -40,12 +30,6 @@ class FakeLogService : LogService { severity = severity, logExceptionType = logExceptionType, properties = properties, - stackTraceElements = stackTraceElements, - customStackTrace = customStackTrace, - context = context, - library = library, - exceptionName = exceptionName, - exceptionMessage = exceptionMessage ) ) } @@ -54,7 +38,5 @@ class FakeLogService : LogService { return errorLogIds.count() } - override fun cleanCollections() { - TODO("Not yet implemented") - } + override fun cleanCollections() {} } diff --git a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/injection/FakeLogModule.kt b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/injection/FakeLogModule.kt index 5de336d19c..6c36977c3e 100644 --- a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/injection/FakeLogModule.kt +++ b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/injection/FakeLogModule.kt @@ -14,7 +14,6 @@ import io.embrace.android.embracesdk.internal.logs.LogService import io.embrace.android.embracesdk.internal.network.logging.NetworkCaptureDataSource import io.embrace.android.embracesdk.internal.network.logging.NetworkCaptureService import io.embrace.android.embracesdk.internal.network.logging.NetworkLoggingService -import io.embrace.android.embracesdk.internal.serialization.EmbraceSerializer class FakeLogModule( override val networkLoggingService: NetworkLoggingService = FakeNetworkLoggingService(), @@ -22,8 +21,7 @@ class FakeLogModule( override val logService: LogService = EmbraceLogService( FakeLogWriter(), FakeConfigService(), - FakeSessionPropertiesService(), - EmbraceSerializer() + FakeSessionPropertiesService() ), ) : LogModule {