Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ ${next_release_notes}
===== Features

* Sending app's versionCode in the `service.build` attribute: {pull}153[#153]
* Sending app's lifecycle events: {pull}159[#159]
////

[[release-notes-0.6.0]]
Expand Down
1 change: 1 addition & 0 deletions NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Copyright 2018-2022 Elasticsearch B.V.

This product includes software licensed under the 'Apache License Version 2.0' license from the following sources:

- Android Lifecycle Process (https://developer.android.com/jetpack/androidx/releases/lifecycle#2.5.1)
- Android Support Library Annotations (https://developer.android.com/jetpack/androidx/releases/annotation#1.4.0)
- Android Support Library fragment (https://developer.android.com/jetpack/androidx/releases/fragment#1.5.3)
- Byte Buddy (without dependencies)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
#Tue Mar 07 09:53:14 CET 2023
#Thu Apr 27 12:29:37 CEST 2023
dependencies.hash=D41D8CD98F00B204E9800998ECF8427E
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
#Tue Mar 07 09:53:14 CET 2023
#Thu Apr 27 12:29:37 CEST 2023
dependencies.hash=D41D8CD98F00B204E9800998ECF8427E
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
#Tue Mar 07 09:53:14 CET 2023
#Thu Apr 27 12:29:37 CEST 2023
dependencies.hash=D41D8CD98F00B204E9800998ECF8427E
2 changes: 1 addition & 1 deletion android-common/metadata/notice.properties
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
#Tue Mar 07 09:53:14 CET 2023
#Thu Apr 27 12:29:37 CEST 2023
dependencies.hash=C4E938CB5D2FBDF87B030546B2E27163
2 changes: 1 addition & 1 deletion android-instrumentation/metadata/notice.properties
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
#Mon Feb 27 10:11:36 CET 2023
#Thu Apr 27 12:29:37 CEST 2023
dependencies.hash=A3B09917BB285EF396AF771F4773CA88
2 changes: 1 addition & 1 deletion android-plugin/metadata/notice.properties
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
#Mon Feb 27 10:11:35 CET 2023
#Thu Apr 27 12:29:37 CEST 2023
dependencies.hash=0DD08B094996DCF2A76E9BDCF6AAD579
2 changes: 1 addition & 1 deletion android-sdk-ktx/metadata/notice.properties
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
#Mon Feb 27 10:11:36 CET 2023
#Thu Apr 27 12:29:37 CEST 2023
dependencies.hash=359431A1C90E82A5470B06EDEEBC764A
1 change: 1 addition & 0 deletions android-sdk/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ dependencies {
api "io.opentelemetry:opentelemetry-sdk-logs:$openTelemetry_version-alpha"
api "com.squareup.okhttp3:okhttp:$okhttp_version"
api 'org.stagemonitor:stagemonitor-configuration:0.89.1'
implementation "androidx.lifecycle:lifecycle-process:2.5.1"
implementation 'com.blogspot.mydailyjava:weak-lock-free:0.18'
implementation project(':android-common')
implementation "io.opentelemetry:opentelemetry-exporter-otlp:$openTelemetry_version"
Expand Down
4 changes: 2 additions & 2 deletions android-sdk/metadata/notice.properties
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
#Tue Mar 07 09:53:14 CET 2023
dependencies.hash=5BB3BE3A40061E90457413DAA9A91E03
#Thu Apr 27 12:29:37 CEST 2023
dependencies.hash=2B4DA6DF07C8631523A0FDB5D9DDB7A4
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import android.content.Context;

import androidx.annotation.RestrictTo;
import androidx.lifecycle.ProcessLifecycleOwner;

import co.elastic.apm.android.common.internal.logging.Elog;
import co.elastic.apm.android.sdk.attributes.AttributesCreator;
Expand All @@ -45,6 +46,7 @@
import co.elastic.apm.android.sdk.internal.features.centralconfig.initializer.CentralConfigurationInitializer;
import co.elastic.apm.android.sdk.internal.features.centralconfig.poll.ConfigurationPollManager;
import co.elastic.apm.android.sdk.internal.features.launchtime.LaunchTimeActivityCallback;
import co.elastic.apm.android.sdk.internal.features.lifecycle.ElasticProcessLifecycleObserver;
import co.elastic.apm.android.sdk.internal.injection.AgentDependenciesInjector;
import co.elastic.apm.android.sdk.internal.injection.DefaultAgentDependenciesInjector;
import co.elastic.apm.android.sdk.internal.opentelemetry.ElasticOpenTelemetry;
Expand Down Expand Up @@ -152,6 +154,11 @@ private void onInitializationFinished(Context context, AgentDependenciesInjector
initializeCrashReports();
initializeSessionIdProvider();
initializeLaunchTimeTracker(context);
initializeLifecycleObserver();
}

private void initializeLifecycleObserver() {
ProcessLifecycleOwner.get().getLifecycle().addObserver(new ElasticProcessLifecycleObserver());
}

private void initializeNtpManager(AgentDependenciesInjector injector) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package co.elastic.apm.android.sdk.internal.features.lifecycle;

import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.LifecycleOwner;

import co.elastic.apm.android.sdk.logs.ElasticLoggers;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.logs.Logger;

public class ElasticProcessLifecycleObserver implements DefaultLifecycleObserver {
private final Logger lifecycleLogger;

@VisibleForTesting
public ElasticProcessLifecycleObserver(Logger lifecycleLogger) {
this.lifecycleLogger = lifecycleLogger;
}

public ElasticProcessLifecycleObserver() {
this(ElasticLoggers.lifecycleReporter());
}

@Override
public void onCreate(@NonNull LifecycleOwner owner) {
emitLifecycleState("created");
}

@Override
public void onStart(@NonNull LifecycleOwner owner) {
emitLifecycleState("started");
}

@Override
public void onResume(@NonNull LifecycleOwner owner) {
emitLifecycleState("resumed");
}

@Override
public void onPause(@NonNull LifecycleOwner owner) {
emitLifecycleState("paused");
}

@Override
public void onStop(@NonNull LifecycleOwner owner) {
emitLifecycleState("stopped");
}

private void emitLifecycleState(String value) {
lifecycleLogger.eventBuilder("lifecycle")
.setAttribute(AttributeKey.stringKey("lifecycle.state"), value)
.emit();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,15 @@
public final class ElasticLoggers {

public static Logger crashReporter() {
return builder("CrashReport")
.setEventDomain("device").build();
return builder("CrashReport").build();
}

public static Logger lifecycleReporter() {
return builder("ApplicationLifecycle").build();
}

public static LoggerBuilder builder(String instrumentationScopeName) {
return GlobalLoggerProvider.get().loggerBuilder(instrumentationScopeName);
return GlobalLoggerProvider.get().loggerBuilder(instrumentationScopeName)
.setEventDomain("device");
}
}
1 change: 1 addition & 0 deletions android-sdk/src/main/resources/META-INF/NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Copyright 2018-2022 Elasticsearch B.V.

This product includes software licensed under the 'Apache License Version 2.0' license from the following sources:

- Android Lifecycle Process (https://developer.android.com/jetpack/androidx/releases/lifecycle#2.5.1)
- Android Support Library Annotations (https://developer.android.com/jetpack/androidx/releases/annotation#1.4.0)
- com.github.instacart.truetime-android:library:3.5
- okhttp (https://square.github.io/okhttp/)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package co.elastic.apm.android.sdk.internal.features.lifecycle;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.verifyNoMoreInteractions;

import androidx.lifecycle.LifecycleOwner;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.logs.EventBuilder;
import io.opentelemetry.api.logs.Logger;

public class ElasticProcessLifecycleObserverTest {

private ElasticProcessLifecycleObserver instance;
private LifecycleOwner owner;
private Logger logger;
private EventBuilder builder;

@Before
public void setUp() {
logger = mock(Logger.class);
owner = mock(LifecycleOwner.class);
builder = mock(EventBuilder.class);
doReturn(builder).when(logger).eventBuilder(anyString());
doReturn(builder).when(builder).setAttribute(any(), any());
instance = new ElasticProcessLifecycleObserver(logger);
}

@Test
public void verifyCreatedEvent() {
instance.onCreate(owner);

verifyLifecycleEvent("created");
}

@Test
public void verifyStartedEvent() {
instance.onStart(owner);

verifyLifecycleEvent("started");
}

@Test
public void verifyResumedEvent() {
instance.onResume(owner);

verifyLifecycleEvent("resumed");
}

@Test
public void verifyPausedEvent() {
instance.onPause(owner);

verifyLifecycleEvent("paused");
}

@Test
public void verifyStoppedEvent() {
instance.onStop(owner);

verifyLifecycleEvent("stopped");
}

private void verifyLifecycleEvent(String state) {
verifyEventName();
verifyStateAttribute(state);
verify(builder).emit();
}

private void verifyStateAttribute(String value) {
verify(builder).setAttribute(AttributeKey.stringKey("lifecycle.state"), value);
}

private void verifyEventName() {
verify(logger).eventBuilder("lifecycle");
}

@After
public void tearDown() {
verifyNoMoreInteractions(builder);
verifyNoMoreInteractions(logger);
verifyNoInteractions(owner);
}
}