Skip to content

Commit

Permalink
Enhancing internal logging (#245)
Browse files Browse the repository at this point in the history
* Created LoggingPolicy and LogLevel

* Created DefaultLoggingPolicy

* Making library logging policy configurable

* Ussing logging policy in AndroidLogger

* Not creating logs when the agent is not initialized as part of the default logging policy

* Enhancing LoggingPolicy convenience methods

* Updating configuration.asciidoc to include new library logging policy config

* Update docs/configuration.asciidoc

Co-authored-by: Brandon Morelli <[email protected]>

* Updating logging policy docs

---------

Co-authored-by: Brandon Morelli <[email protected]>
  • Loading branch information
LikeTheSalad and bmorelli25 authored Dec 12, 2023
1 parent 1b3e115 commit 4f94091
Show file tree
Hide file tree
Showing 13 changed files with 471 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,10 @@ private synchronized static ElasticApmAgent initialize(Context context, ElasticA
throw new IllegalStateException("Already initialized");
}
Context appContext = context.getApplicationContext();
Elog.init(new AndroidLoggerFactory());
ElasticApmConfiguration finalConfiguration = (configuration == null) ? ElasticApmConfiguration.getDefault() : configuration;
Elog.init(new AndroidLoggerFactory(finalConfiguration.libraryLoggingPolicy));
ServiceManager.initialize(appContext);
ServiceManager.get().start();
ElasticApmConfiguration finalConfiguration = (configuration == null) ? ElasticApmConfiguration.getDefault() : configuration;
Connectivity finalConnectivity = (connectivity == null) ? Connectivity.getDefault() : connectivity;
AgentDependenciesInjector injector = process(new DefaultAgentDependenciesInjector(appContext, finalConfiguration, finalConnectivity), interceptor);
instance = new ElasticApmAgent(finalConfiguration);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import java.util.List;
import java.util.Set;

import co.elastic.apm.android.sdk.configuration.logging.LogLevel;
import co.elastic.apm.android.sdk.configuration.logging.LoggingPolicy;
import co.elastic.apm.android.sdk.connectivity.ExportProtocol;
import co.elastic.apm.android.sdk.connectivity.opentelemetry.SignalConfiguration;
import co.elastic.apm.android.sdk.features.persistence.PersistenceConfiguration;
Expand All @@ -49,6 +51,7 @@ public final class ElasticApmConfiguration {
public final List<SpanFilter> spanFilters;
public final List<LogFilter> logFilters;
public final List<MetricFilter> metricFilters;
public final LoggingPolicy libraryLoggingPolicy;

public static Builder builder() {
return new Builder();
Expand All @@ -69,6 +72,7 @@ private ElasticApmConfiguration(Builder builder) {
persistenceConfiguration = builder.persistenceConfiguration;
sampleRate = builder.sampleRate;
exportProtocol = builder.exportProtocol;
libraryLoggingPolicy = builder.libraryLoggingPolicy;
spanFilters = Collections.unmodifiableList(new ArrayList<>(builder.spanFilters));
logFilters = Collections.unmodifiableList(new ArrayList<>(builder.logFilters));
metricFilters = Collections.unmodifiableList(new ArrayList<>(builder.metricFilters));
Expand All @@ -85,6 +89,7 @@ public static class Builder {
private SignalConfiguration signalConfiguration;
private double sampleRate = 1.0;
private ExportProtocol exportProtocol = ExportProtocol.GRPC;
private LoggingPolicy libraryLoggingPolicy = LoggingPolicy.getDefault();
private final Set<SpanFilter> spanFilters = new HashSet<>();
private final Set<LogFilter> logFilters = new HashSet<>();
private final Set<MetricFilter> metricFilters = new HashSet<>();
Expand Down Expand Up @@ -191,6 +196,15 @@ public Builder setExportProtocol(ExportProtocol exportProtocol) {
return this;
}

/**
* Sets the logging policy for this library's internal logs. By default, it will log all the {@link LogLevel}s on debuggable applications
* and only logs from level INFO and above for non-debuggable applications.
*/
public Builder setLibraryLoggingPolicy(LoggingPolicy libraryLoggingPolicy) {
this.libraryLoggingPolicy = libraryLoggingPolicy;
return this;
}

/**
* The span filter can be used to control which spans are exported and which shouldn't
* leave the device. An implementation that always excludes all spans is essentially a way
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* 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.configuration.logging;

public enum LogLevel {
TRACE(0), DEBUG(1), INFO(2), WARN(3), ERROR(4);

public final int value;

LogLevel(int value) {
this.value = value;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* 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.configuration.logging;

import co.elastic.apm.android.sdk.configuration.logging.impl.DefaultLoggingPolicy;
import co.elastic.apm.android.sdk.configuration.logging.impl.SimpleLoggingPolicy;

/**
* Defines the internal logging behavior of this library.
*/
public interface LoggingPolicy {

/**
* Provides the default logging policy which will log all the {@link LogLevel}s on debuggable applications
* and only logs from level INFO and above for non-debuggable applications.
* <p>
* No logs will be created until the Agent is initialized.
*/
static LoggingPolicy getDefault() {
return DefaultLoggingPolicy.create();
}

/**
* Convenience method for creating an enabled logging policy with a static minimum level.
*
* @param minimumLevel - The minimum {@link LogLevel}, all the logs with this level and above will get printed, others will be ignored.
*/
static LoggingPolicy enabled(LogLevel minimumLevel) {
return new SimpleLoggingPolicy(true, minimumLevel);
}

/**
* Convenience method for creating a policy that disables all internal logs.
*/
static LoggingPolicy disabled() {
return new SimpleLoggingPolicy(false, LogLevel.TRACE);
}

/**
* Whether logging in general is enabled or not. This value will be checked before the log level.
*/
boolean isEnabled();

/**
* If logging is enabled, this value will be checked later to filter which logs will
* get printed. Logs with at least the level provided here or higher will pass, other ones (below the level provided here) will be ignored.
*/
LogLevel getMinimumLevel();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* 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.configuration.logging.impl;

import co.elastic.apm.android.sdk.ElasticApmAgent;
import co.elastic.apm.android.sdk.configuration.logging.LogLevel;
import co.elastic.apm.android.sdk.configuration.logging.LoggingPolicy;
import co.elastic.apm.android.sdk.internal.services.Service;
import co.elastic.apm.android.sdk.internal.services.ServiceManager;
import co.elastic.apm.android.sdk.internal.services.appinfo.AppInfoService;
import co.elastic.apm.android.sdk.internal.utilities.providers.LazyProvider;
import co.elastic.apm.android.sdk.internal.utilities.providers.Provider;

public class DefaultLoggingPolicy implements LoggingPolicy {

private final Provider<Boolean> appIsDebuggable;
private final Provider<Boolean> agentIsInitialized;

public static DefaultLoggingPolicy create() {
final Provider<Boolean> agentIsInitialized = ElasticApmAgent::isInitialized;
return new DefaultLoggingPolicy(LazyProvider.of(() -> {
if (!agentIsInitialized.get()) {
return false;
}
AppInfoService service = ServiceManager.get().getService(Service.Names.APP_INFO);
return service.isInDebugMode();
}), agentIsInitialized);
}

public DefaultLoggingPolicy(Provider<Boolean> appIsDebuggable, Provider<Boolean> agentIsInitialized) {
this.appIsDebuggable = appIsDebuggable;
this.agentIsInitialized = agentIsInitialized;
}

@Override
public boolean isEnabled() {
return agentIsInitialized.get();
}

@Override
public LogLevel getMinimumLevel() {
return (appIsDebuggable.get()) ? LogLevel.DEBUG : LogLevel.INFO;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* 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.configuration.logging.impl;

import co.elastic.apm.android.sdk.configuration.logging.LogLevel;
import co.elastic.apm.android.sdk.configuration.logging.LoggingPolicy;

public final class SimpleLoggingPolicy implements LoggingPolicy {
private final boolean isEnabled;
private final LogLevel minimumLevel;

public SimpleLoggingPolicy(boolean isEnabled, LogLevel minimumLevel) {
this.isEnabled = isEnabled;
this.minimumLevel = minimumLevel;
}

@Override
public boolean isEnabled() {
return isEnabled;
}

@Override
public LogLevel getMinimumLevel() {
return minimumLevel;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,12 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import co.elastic.apm.android.common.internal.logging.Elog;
import co.elastic.apm.android.sdk.internal.features.launchtime.LaunchTimeTracker;
import co.elastic.apm.android.sdk.internal.utilities.logging.AndroidLoggerFactory;

public final class ElasticInitializer extends ContentProvider {

@Override
public boolean onCreate() {
Elog.init(new AndroidLoggerFactory());
LaunchTimeTracker.startTimer();
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,15 @@
import org.slf4j.event.Level;

import co.elastic.apm.android.common.internal.logging.BaseELogger;
import co.elastic.apm.android.sdk.ElasticApmAgent;
import co.elastic.apm.android.sdk.internal.services.Service;
import co.elastic.apm.android.sdk.internal.services.ServiceManager;
import co.elastic.apm.android.sdk.internal.services.appinfo.AppInfoService;
import co.elastic.apm.android.sdk.internal.utilities.providers.LazyProvider;
import co.elastic.apm.android.sdk.configuration.logging.LogLevel;
import co.elastic.apm.android.sdk.configuration.logging.LoggingPolicy;

class AndroidLogger extends BaseELogger {
private final LazyProvider<Boolean> appIsDebuggable;
private final LoggingPolicy policy;

AndroidLogger(String tag) {
AndroidLogger(String tag, LoggingPolicy policy) {
super(tag);
appIsDebuggable = LazyProvider.of(() -> {
if (!ElasticApmAgent.isInitialized()) {
return false;
}
AppInfoService service = ServiceManager.get().getService(Service.Names.APP_INFO);
return service.isInDebugMode();
});
this.policy = policy;
}

@Override
Expand All @@ -66,26 +57,34 @@ protected void handleLoggingCall(Level level, String formattedMessage, Throwable

@Override
public boolean isTraceEnabled() {
return appIsDebuggable.get();
return checkIfEnabledFor(LogLevel.TRACE);
}

@Override
public boolean isDebugEnabled() {
return appIsDebuggable.get();
return checkIfEnabledFor(LogLevel.DEBUG);
}

@Override
public boolean isInfoEnabled() {
return true;
return checkIfEnabledFor(LogLevel.INFO);
}

@Override
public boolean isWarnEnabled() {
return true;
return checkIfEnabledFor(LogLevel.WARN);
}

@Override
public boolean isErrorEnabled() {
return true;
return checkIfEnabledFor(LogLevel.ERROR);
}

private boolean checkIfEnabledFor(LogLevel logLevel) {
if (!policy.isEnabled()) {
return false;
}

return logLevel.value >= policy.getMinimumLevel().value;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,17 @@
import org.slf4j.Logger;

import co.elastic.apm.android.common.internal.logging.ELoggerFactory;
import co.elastic.apm.android.sdk.configuration.logging.LoggingPolicy;

public class AndroidLoggerFactory extends ELoggerFactory {
private final LoggingPolicy policy;

public AndroidLoggerFactory(LoggingPolicy policy) {
this.policy = policy;
}

@Override
public Logger getLogger(String name) {
return new AndroidLogger(name);
return new AndroidLogger(name, policy);
}
}
Loading

0 comments on commit 4f94091

Please sign in to comment.