forked from organicmaps/organicmaps
[android] Refactor logging
- more reliable fallback to system log if file logging is not available - fix DEBUG core messages not logged after file logging is switched off - add log messages to facilitate debugging logging issues Signed-off-by: Konstantin Pastbin <konstantin.pastbin@gmail.com>
This commit is contained in:
parent
3e4e7f4ec4
commit
48a8d2aba5
6 changed files with 81 additions and 86 deletions
|
@ -44,7 +44,7 @@ public class MwmApplication extends Application implements AppBackgroundTracker.
|
|||
{
|
||||
@SuppressWarnings("NotNullFieldNotInitialized")
|
||||
@NonNull
|
||||
private Logger mLogger;
|
||||
private final Logger mLogger = LoggerFactory.INSTANCE.getLogger(LoggerFactory.Type.MISC);
|
||||
public final static String TAG = "MwmApplication";
|
||||
|
||||
private AppBackgroundTracker mBackgroundTracker;
|
||||
|
@ -100,8 +100,7 @@ public class MwmApplication extends Application implements AppBackgroundTracker.
|
|||
@NonNull
|
||||
public static SharedPreferences prefs(@NonNull Context context)
|
||||
{
|
||||
String prefFile = context.getString(R.string.pref_file_name);
|
||||
return context.getSharedPreferences(prefFile, MODE_PRIVATE);
|
||||
return context.getSharedPreferences(context.getString(R.string.pref_file_name), MODE_PRIVATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -116,13 +115,13 @@ public class MwmApplication extends Application implements AppBackgroundTracker.
|
|||
public void onCreate()
|
||||
{
|
||||
super.onCreate();
|
||||
LoggerFactory.INSTANCE.initialize(this);
|
||||
mLogger = LoggerFactory.INSTANCE.getLogger(LoggerFactory.Type.MISC);
|
||||
getLogger().d(TAG, "Application is created");
|
||||
mLogger.i(TAG, "Initializing application");
|
||||
LoggerFactory.INSTANCE.initFileLogging(this);
|
||||
|
||||
// Set configuration directory as early as possible.
|
||||
// Other methods may explicitly use Config, which requires settingsDir to be set.
|
||||
final String settingsPath = StorageUtils.getSettingsPath(this);
|
||||
getLogger().d(TAG, "Settings path = " + settingsPath);
|
||||
mLogger.d(TAG, "Settings path = " + settingsPath);
|
||||
try
|
||||
{
|
||||
StorageUtils.createDirectory(settingsPath);
|
||||
|
@ -168,16 +167,15 @@ public class MwmApplication extends Application implements AppBackgroundTracker.
|
|||
if (mPlatformInitialized)
|
||||
return;
|
||||
|
||||
final Logger log = getLogger();
|
||||
final String apkPath = StorageUtils.getApkPath(this);
|
||||
log.d(TAG, "Apk path = " + apkPath);
|
||||
mLogger.d(TAG, "Apk path = " + apkPath);
|
||||
// Note: StoragePathManager uses Config, which requires initConfig() to be called.
|
||||
final String writablePath = StoragePathManager.findMapsStorage(this);
|
||||
log.d(TAG, "Writable path = " + writablePath);
|
||||
mLogger.d(TAG, "Writable path = " + writablePath);
|
||||
final String privatePath = StorageUtils.getPrivatePath(this);
|
||||
log.d(TAG, "Private path = " + privatePath);
|
||||
mLogger.d(TAG, "Private path = " + privatePath);
|
||||
final String tempPath = StorageUtils.getTempPath(this);
|
||||
log.d(TAG, "Temp path = " + tempPath);
|
||||
mLogger.d(TAG, "Temp path = " + tempPath);
|
||||
|
||||
// If platform directories are not created it means that native part of app will not be able
|
||||
// to work at all. So, we just ignore native part initialization in this case, e.g. when the
|
||||
|
@ -195,7 +193,7 @@ public class MwmApplication extends Application implements AppBackgroundTracker.
|
|||
|
||||
Editor.init(this);
|
||||
mPlatformInitialized = true;
|
||||
log.i(TAG, "Platform initialized");
|
||||
mLogger.i(TAG, "Platform initialized");
|
||||
}
|
||||
|
||||
private void createPlatformDirectories(@NonNull String writablePath,
|
||||
|
@ -231,7 +229,7 @@ public class MwmApplication extends Application implements AppBackgroundTracker.
|
|||
IsolinesManager.from(this).initialize(null);
|
||||
mBackgroundTracker.addListener(this);
|
||||
|
||||
getLogger().i(TAG, "Framework initialized");
|
||||
mLogger.i(TAG, "Framework initialized");
|
||||
mFrameworkInitialized = true;
|
||||
}
|
||||
|
||||
|
@ -297,12 +295,6 @@ public class MwmApplication extends Application implements AppBackgroundTracker.
|
|||
private static native void nativeAddLocalization(String name, String value);
|
||||
private static native void nativeOnTransit(boolean foreground);
|
||||
|
||||
@NonNull
|
||||
public Logger getLogger()
|
||||
{
|
||||
return mLogger;
|
||||
}
|
||||
|
||||
public boolean isFirstLaunch()
|
||||
{
|
||||
return mFirstLaunch;
|
||||
|
|
|
@ -21,7 +21,6 @@ import androidx.preference.Preference;
|
|||
import androidx.preference.PreferenceCategory;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.preference.TwoStatePreference;
|
||||
|
||||
import com.mapswithme.maps.Framework;
|
||||
import com.mapswithme.maps.R;
|
||||
import com.mapswithme.maps.downloader.MapManager;
|
||||
|
@ -481,16 +480,11 @@ public class SettingsPrefsFragment extends BaseXmlSettingsFragment
|
|||
if (pref == null)
|
||||
return;
|
||||
|
||||
final boolean isLoggingEnabled = LoggerFactory.INSTANCE.isFileLoggingEnabled();
|
||||
((TwoStatePreference) pref).setChecked(isLoggingEnabled);
|
||||
pref.setOnPreferenceChangeListener(
|
||||
(preference, newValue) ->
|
||||
{
|
||||
boolean newVal = (Boolean) newValue;
|
||||
if (isLoggingEnabled != newVal)
|
||||
LoggerFactory.INSTANCE.setFileLoggingEnabled(newVal);
|
||||
return true;
|
||||
});
|
||||
((TwoStatePreference) pref).setChecked(LoggerFactory.INSTANCE.isFileLoggingEnabled);
|
||||
pref.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
LoggerFactory.INSTANCE.setFileLoggingEnabled((Boolean) newValue);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void initEmulationBadStorage()
|
||||
|
|
|
@ -66,8 +66,7 @@ public class StorageUtils
|
|||
if (dir != null)
|
||||
return dir.getAbsolutePath();
|
||||
|
||||
Log.e(StorageUtils.class.getSimpleName(),
|
||||
"Cannot get the external files directory for some reasons", new Throwable());
|
||||
Log.e(TAG, "Cannot get the external files directory for some reasons", new Throwable());
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,11 +9,9 @@ import android.os.Build;
|
|||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.mapswithme.maps.BuildConfig;
|
||||
import com.mapswithme.util.StorageUtils;
|
||||
import com.mapswithme.util.Utils;
|
||||
|
||||
import net.jcip.annotations.Immutable;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -36,8 +34,8 @@ class FileLoggerStrategy implements LoggerStrategy
|
|||
@NonNull
|
||||
private final Application mApplication;
|
||||
|
||||
FileLoggerStrategy(@NonNull Application application, @NonNull String filePath,
|
||||
@NonNull Executor executor)
|
||||
public FileLoggerStrategy(@NonNull Application application, @NonNull String filePath,
|
||||
@NonNull Executor executor)
|
||||
{
|
||||
mApplication = application;
|
||||
mFilePath = filePath;
|
||||
|
|
|
@ -1,39 +1,43 @@
|
|||
package com.mapswithme.util.log;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.mapswithme.maps.BuildConfig;
|
||||
|
||||
import net.jcip.annotations.Immutable;
|
||||
|
||||
@Immutable
|
||||
class LogCatStrategy implements LoggerStrategy
|
||||
{
|
||||
private final boolean mIsDebug;
|
||||
|
||||
public LogCatStrategy(final boolean isDebug)
|
||||
{
|
||||
mIsDebug = isDebug;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void v(String tag, String msg)
|
||||
{
|
||||
if (canLog())
|
||||
if (mIsDebug)
|
||||
Log.v(tag, msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void v(String tag, String msg, Throwable tr)
|
||||
{
|
||||
if (canLog())
|
||||
if (mIsDebug)
|
||||
Log.v(tag, msg, tr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void d(String tag, String msg)
|
||||
{
|
||||
if (canLog())
|
||||
if (mIsDebug)
|
||||
Log.d(tag, msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void d(String tag, String msg, Throwable tr)
|
||||
{
|
||||
if (canLog())
|
||||
if (mIsDebug)
|
||||
Log.d(tag, msg, tr);
|
||||
}
|
||||
|
||||
|
@ -78,9 +82,4 @@ class LogCatStrategy implements LoggerStrategy
|
|||
{
|
||||
Log.e(tag, msg, tr);
|
||||
}
|
||||
|
||||
private static boolean canLog()
|
||||
{
|
||||
return BuildConfig.DEBUG;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,13 +7,10 @@ import android.util.Log;
|
|||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.mapswithme.maps.BuildConfig;
|
||||
import com.mapswithme.maps.MwmApplication;
|
||||
import com.mapswithme.maps.R;
|
||||
import com.mapswithme.util.CrashlyticsUtils;
|
||||
import com.mapswithme.util.StorageUtils;
|
||||
|
||||
import net.jcip.annotations.GuardedBy;
|
||||
import net.jcip.annotations.ThreadSafe;
|
||||
|
||||
|
@ -23,6 +20,10 @@ import java.util.Objects;
|
|||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
/**
|
||||
* By default uses Android's system logger.
|
||||
* After an initFileLogging() call can use a custom file logging implementation.
|
||||
*/
|
||||
@ThreadSafe
|
||||
public class LoggerFactory
|
||||
{
|
||||
|
@ -45,50 +46,63 @@ public class LoggerFactory
|
|||
}
|
||||
|
||||
public final static LoggerFactory INSTANCE = new LoggerFactory();
|
||||
public boolean isFileLoggingEnabled = false;
|
||||
|
||||
@NonNull
|
||||
@GuardedBy("this")
|
||||
private final EnumMap<Type, BaseLogger> mLoggers = new EnumMap<>(Type.class);
|
||||
private final static String CORE_TAG = "OMapsCore";
|
||||
private final static String TAG = LoggerFactory.class.getSimpleName();
|
||||
private final static String CORE_TAG = "OMcore";
|
||||
@Nullable
|
||||
@GuardedBy("this")
|
||||
private ExecutorService mFileLoggerExecutor;
|
||||
@Nullable
|
||||
private Application mApplication;
|
||||
private String mLogsFolder;
|
||||
|
||||
private LoggerFactory()
|
||||
{
|
||||
Log.i(LoggerFactory.class.getSimpleName(), "Logging started");
|
||||
}
|
||||
|
||||
public void initialize(@NonNull Application application)
|
||||
public void initFileLogging(@NonNull Application application)
|
||||
{
|
||||
getLogger(Type.MISC).i(TAG, "Init file logging");
|
||||
mApplication = application;
|
||||
mLogsFolder = StorageUtils.getLogsFolder(mApplication);
|
||||
|
||||
final SharedPreferences prefs = MwmApplication.prefs(mApplication);
|
||||
// File logging is enabled by default for beta builds.
|
||||
isFileLoggingEnabled = prefs.getBoolean(mApplication.getString(R.string.pref_enable_logging),
|
||||
BuildConfig.BUILD_TYPE.equals("beta"));
|
||||
getLogger(Type.MISC).i(TAG, "Logging config: isFileLoggingEnabled: " + isFileLoggingEnabled +
|
||||
"; logs folder: " + mLogsFolder);
|
||||
|
||||
// Set native logging level, save into shared preferences, update already created loggers if any.
|
||||
switchFileLoggingEnabled(isFileLoggingEnabled);
|
||||
}
|
||||
|
||||
public boolean isFileLoggingEnabled()
|
||||
private void switchFileLoggingEnabled(boolean enabled)
|
||||
{
|
||||
if (mApplication == null)
|
||||
{
|
||||
if (BuildConfig.DEBUG)
|
||||
throw new IllegalStateException("Application is not created," +
|
||||
"but logger is used!");
|
||||
return false;
|
||||
}
|
||||
|
||||
SharedPreferences prefs = MwmApplication.prefs(mApplication);
|
||||
String enableLoggingKey = mApplication.getString(R.string.pref_enable_logging);
|
||||
//noinspection ConstantConditions
|
||||
return prefs.getBoolean(enableLoggingKey, BuildConfig.BUILD_TYPE.equals("beta"));
|
||||
getLogger(Type.MISC).i(TAG, "Switch isFileLoggingEnabled to " + enabled);
|
||||
isFileLoggingEnabled = enabled;
|
||||
nativeToggleCoreDebugLogs(enabled || BuildConfig.DEBUG);
|
||||
MwmApplication.prefs(mApplication)
|
||||
.edit()
|
||||
.putBoolean(mApplication.getString(R.string.pref_enable_logging), enabled)
|
||||
.apply();
|
||||
updateLoggers();
|
||||
getLogger(Type.MISC).i(TAG, "File logging " + (enabled ? " started to " + mLogsFolder : "stopped"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws a NullPointerException if initFileLogging() was not called before.
|
||||
*/
|
||||
public void setFileLoggingEnabled(boolean enabled)
|
||||
{
|
||||
Objects.requireNonNull(mApplication);
|
||||
nativeToggleCoreDebugLogs(enabled);
|
||||
SharedPreferences prefs = MwmApplication.prefs(mApplication);
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
String enableLoggingKey = mApplication.getString(R.string.pref_enable_logging);
|
||||
editor.putBoolean(enableLoggingKey, enabled).apply();
|
||||
updateLoggers();
|
||||
if (isFileLoggingEnabled != enabled)
|
||||
switchFileLoggingEnabled(enabled);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
@ -112,21 +126,22 @@ public class LoggerFactory
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Does nothing if initFileLogging() was not called before.
|
||||
*/
|
||||
public synchronized void zipLogs(@Nullable OnZipCompletedListener listener)
|
||||
{
|
||||
if (mApplication == null)
|
||||
return;
|
||||
|
||||
String logsFolder = StorageUtils.getLogsFolder(mApplication);
|
||||
|
||||
if (TextUtils.isEmpty(logsFolder))
|
||||
if (TextUtils.isEmpty(mLogsFolder))
|
||||
{
|
||||
if (listener != null)
|
||||
listener.onCompleted(false);
|
||||
return;
|
||||
}
|
||||
|
||||
Runnable task = new ZipLogsTask(mApplication, logsFolder, logsFolder + ".zip", listener);
|
||||
Runnable task = new ZipLogsTask(mApplication, mLogsFolder, mLogsFolder + ".zip", listener);
|
||||
getFileLoggerExecutor().execute(task);
|
||||
}
|
||||
|
||||
|
@ -140,16 +155,15 @@ public class LoggerFactory
|
|||
@NonNull
|
||||
private LoggerStrategy createLoggerStrategy(@NonNull Type type)
|
||||
{
|
||||
if (isFileLoggingEnabled() && mApplication != null)
|
||||
if (isFileLoggingEnabled && mApplication != null)
|
||||
{
|
||||
nativeToggleCoreDebugLogs(true);
|
||||
String logsFolder = StorageUtils.getLogsFolder(mApplication);
|
||||
if (!TextUtils.isEmpty(logsFolder))
|
||||
return new FileLoggerStrategy(mApplication,logsFolder + File.separator
|
||||
+ type.name().toLowerCase() + ".log", getFileLoggerExecutor());
|
||||
if (!TextUtils.isEmpty(mLogsFolder))
|
||||
{
|
||||
return new FileLoggerStrategy(mApplication, mLogsFolder + File.separator + type.name()
|
||||
.toLowerCase() + ".log", getFileLoggerExecutor());
|
||||
}
|
||||
}
|
||||
|
||||
return new LogCatStrategy();
|
||||
return new LogCatStrategy(isFileLoggingEnabled || BuildConfig.DEBUG);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
@ -182,7 +196,6 @@ public class LoggerFactory
|
|||
default:
|
||||
logger.v(CORE_TAG, msg);
|
||||
}
|
||||
CrashlyticsUtils.INSTANCE.log(level, CORE_TAG, msg);
|
||||
}
|
||||
|
||||
private static native void nativeToggleCoreDebugLogs(boolean enabled);
|
||||
|
|
Loading…
Add table
Reference in a new issue