2021-01-10 23:37:09 +01:00
|
|
|
/* Copyright (C) 2016-2021 Carsten Pfeiffer, Daniele Gobbetti, Pavel Elagin
|
2017-03-10 14:53:19 +01:00
|
|
|
|
|
|
|
This file is part of Gadgetbridge.
|
|
|
|
|
|
|
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU Affero General Public License as published
|
|
|
|
by the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
Gadgetbridge is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU Affero General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Affero General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
2016-05-26 23:46:21 +02:00
|
|
|
package nodomain.freeyourgadget.gadgetbridge;
|
|
|
|
|
|
|
|
import android.util.Log;
|
|
|
|
|
|
|
|
import org.slf4j.Logger;
|
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
|
|
|
import ch.qos.logback.classic.LoggerContext;
|
2022-08-07 21:51:48 +02:00
|
|
|
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
|
2016-05-26 23:46:21 +02:00
|
|
|
import ch.qos.logback.classic.spi.ILoggingEvent;
|
|
|
|
import ch.qos.logback.core.Appender;
|
|
|
|
import ch.qos.logback.core.FileAppender;
|
2022-08-07 21:51:48 +02:00
|
|
|
import ch.qos.logback.core.rolling.RollingFileAppender;
|
|
|
|
import ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy;
|
|
|
|
import ch.qos.logback.core.util.FileSize;
|
2016-05-26 23:46:21 +02:00
|
|
|
import ch.qos.logback.core.util.StatusPrinter;
|
2018-06-23 11:15:03 +02:00
|
|
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
2022-10-22 21:53:45 +02:00
|
|
|
import nodomain.freeyourgadget.gadgetbridge.BuildConfig;
|
2016-05-26 23:46:21 +02:00
|
|
|
|
|
|
|
public abstract class Logging {
|
2022-08-07 21:51:48 +02:00
|
|
|
// Only used for tests
|
2016-05-26 23:46:21 +02:00
|
|
|
public static final String PROP_LOGFILES_DIR = "GB_LOGFILES_DIR";
|
|
|
|
|
2022-08-07 21:51:48 +02:00
|
|
|
private String logDirectory;
|
2016-05-26 23:46:21 +02:00
|
|
|
private FileAppender<ILoggingEvent> fileLogger;
|
|
|
|
|
|
|
|
public void setupLogging(boolean enable) {
|
|
|
|
try {
|
2022-08-07 21:51:48 +02:00
|
|
|
if (!isFileLoggerInitialized()) {
|
2016-05-26 23:46:21 +02:00
|
|
|
init();
|
|
|
|
}
|
|
|
|
if (enable) {
|
|
|
|
startFileLogger();
|
|
|
|
} else {
|
|
|
|
stopFileLogger();
|
|
|
|
}
|
2022-10-22 21:53:45 +02:00
|
|
|
getLogger().info("Gadgetbridge version: {}-{}", BuildConfig.VERSION_NAME, BuildConfig.GIT_HASH_SHORT);
|
2022-08-07 21:51:48 +02:00
|
|
|
} catch (Exception ex) {
|
2016-05-26 23:46:21 +02:00
|
|
|
Log.e("GBApplication", "External files dir not available, cannot log to file", ex);
|
|
|
|
stopFileLogger();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-28 14:03:57 +02:00
|
|
|
public String getLogPath() {
|
|
|
|
if (fileLogger != null)
|
|
|
|
return fileLogger.getFile();
|
|
|
|
else
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2022-08-05 20:26:54 +02:00
|
|
|
public boolean isFileLoggerInitialized() {
|
2022-08-07 21:51:48 +02:00
|
|
|
return logDirectory != null;
|
2022-08-05 20:26:54 +02:00
|
|
|
}
|
|
|
|
|
2016-05-26 23:46:21 +02:00
|
|
|
public void debugLoggingConfiguration() {
|
|
|
|
// For debugging problems with the logback configuration
|
|
|
|
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
|
|
|
|
// print logback's internal status
|
|
|
|
StatusPrinter.print(lc);
|
|
|
|
// Logger logger = LoggerFactory.getLogger(Logging.class);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected abstract String createLogDirectory() throws IOException;
|
|
|
|
|
|
|
|
protected void init() throws IOException {
|
2022-08-07 21:51:48 +02:00
|
|
|
Log.i("GBApplication", "Initializing logging");
|
|
|
|
logDirectory = createLogDirectory();
|
|
|
|
if (logDirectory == null) {
|
2016-05-26 23:46:21 +02:00
|
|
|
throw new IllegalArgumentException("log directory must not be null");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private Logger getLogger() {
|
|
|
|
return LoggerFactory.getLogger(Logging.class);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void startFileLogger() {
|
2022-08-07 21:51:48 +02:00
|
|
|
if (fileLogger != null) {
|
|
|
|
Log.w("GBApplication", "Logger already started");
|
|
|
|
return;
|
2016-05-26 23:46:21 +02:00
|
|
|
}
|
|
|
|
|
2022-08-07 21:51:48 +02:00
|
|
|
if (logDirectory == null) {
|
|
|
|
Log.e("GBApplication", "Can't start file logging without a log directory");
|
|
|
|
return;
|
2016-05-26 23:46:21 +02:00
|
|
|
}
|
2022-08-07 21:51:48 +02:00
|
|
|
|
|
|
|
final FileAppender fileAppender = createFileAppender(logDirectory);
|
|
|
|
fileAppender.start();
|
|
|
|
attachLogger(fileAppender);
|
|
|
|
fileLogger = fileAppender;
|
2016-05-26 23:46:21 +02:00
|
|
|
}
|
|
|
|
|
2022-08-07 21:51:48 +02:00
|
|
|
private void stopFileLogger() {
|
2022-08-06 01:31:43 +02:00
|
|
|
if (fileLogger == null) {
|
2022-08-07 21:51:48 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fileLogger.isStarted()) {
|
|
|
|
fileLogger.stop();
|
2022-08-06 01:31:43 +02:00
|
|
|
}
|
2022-08-07 21:51:48 +02:00
|
|
|
|
|
|
|
detachLogger(fileLogger);
|
|
|
|
|
|
|
|
fileLogger = null;
|
2016-05-26 23:46:21 +02:00
|
|
|
}
|
|
|
|
|
2022-08-07 21:51:48 +02:00
|
|
|
private void attachLogger(Appender<ILoggingEvent> logger) {
|
2016-05-26 23:46:21 +02:00
|
|
|
try {
|
|
|
|
ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
|
2022-08-07 21:51:48 +02:00
|
|
|
if (!root.isAttached(logger)) {
|
|
|
|
root.addAppender(logger);
|
2016-05-26 23:46:21 +02:00
|
|
|
}
|
|
|
|
} catch (Throwable ex) {
|
2022-08-07 21:51:48 +02:00
|
|
|
Log.e("GBApplication", "Error attaching logger appender", ex);
|
2016-05-26 23:46:21 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-07 21:51:48 +02:00
|
|
|
private void detachLogger(Appender<ILoggingEvent> logger) {
|
2016-05-26 23:46:21 +02:00
|
|
|
try {
|
|
|
|
ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
|
2022-08-07 21:51:48 +02:00
|
|
|
if (logger != null && root.isAttached(logger)) {
|
|
|
|
root.detachAppender(logger);
|
2016-05-26 23:46:21 +02:00
|
|
|
}
|
|
|
|
} catch (Throwable ex) {
|
2022-08-07 21:51:48 +02:00
|
|
|
Log.e("GBApplication", "Error detaching logger appender", ex);
|
2016-05-26 23:46:21 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public FileAppender<ILoggingEvent> getFileLogger() {
|
|
|
|
return fileLogger;
|
|
|
|
}
|
|
|
|
|
2016-11-18 21:14:04 +01:00
|
|
|
public static String formatBytes(byte[] bytes) {
|
|
|
|
if (bytes == null) {
|
|
|
|
return "(null)";
|
|
|
|
}
|
|
|
|
StringBuilder builder = new StringBuilder(bytes.length * 5);
|
|
|
|
for (byte b : bytes) {
|
2017-10-19 21:52:38 +02:00
|
|
|
builder.append(String.format("0x%02x", b));
|
2016-11-18 21:14:04 +01:00
|
|
|
builder.append(" ");
|
|
|
|
}
|
|
|
|
return builder.toString().trim();
|
|
|
|
}
|
|
|
|
|
2016-10-20 21:42:36 +02:00
|
|
|
public static void logBytes(Logger logger, byte[] value) {
|
|
|
|
if (value != null) {
|
2018-06-23 11:15:03 +02:00
|
|
|
logger.warn("DATA: " + GB.hexdump(value, 0, value.length));
|
2016-10-20 21:42:36 +02:00
|
|
|
}
|
|
|
|
}
|
2022-08-07 21:51:48 +02:00
|
|
|
|
|
|
|
public static FileAppender createFileAppender(final String logDirectory) {
|
|
|
|
final LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
|
|
|
|
|
|
|
|
final PatternLayoutEncoder ple = new PatternLayoutEncoder();
|
|
|
|
//ple.setPattern("%date %level [%thread] %logger{10} [%file:%line] %msg%n");
|
|
|
|
ple.setPattern("%d{HH:mm:ss.SSS} [%thread] %-5level %logger{1} - %msg%n");
|
|
|
|
ple.setContext(lc);
|
|
|
|
ple.start();
|
|
|
|
|
|
|
|
final SizeAndTimeBasedRollingPolicy rollingPolicy = new SizeAndTimeBasedRollingPolicy();
|
|
|
|
final RollingFileAppender<ILoggingEvent> fileAppender = new RollingFileAppender<ILoggingEvent>();
|
|
|
|
|
|
|
|
rollingPolicy.setContext(lc);
|
|
|
|
rollingPolicy.setFileNamePattern(logDirectory + "/gadgetbridge-%d{yyyy-MM-dd}.%i.log.zip");
|
|
|
|
rollingPolicy.setParent(fileAppender);
|
|
|
|
rollingPolicy.setMaxFileSize(FileSize.valueOf("2MB"));
|
|
|
|
rollingPolicy.setMaxHistory(10);
|
|
|
|
rollingPolicy.setTotalSizeCap(FileSize.valueOf("100MB"));
|
|
|
|
rollingPolicy.start();
|
|
|
|
|
|
|
|
fileAppender.setContext(lc);
|
|
|
|
fileAppender.setName("FILE");
|
|
|
|
fileAppender.setLazy(true);
|
|
|
|
fileAppender.setFile(logDirectory + "/gadgetbridge.log");
|
|
|
|
fileAppender.setEncoder(ple);
|
|
|
|
// to debug crashes, set immediateFlush to true, otherwise keep it false to improve throughput
|
|
|
|
fileAppender.setImmediateFlush(false);
|
|
|
|
fileAppender.setRollingPolicy(rollingPolicy);
|
|
|
|
|
|
|
|
return fileAppender;
|
|
|
|
}
|
2016-05-26 23:46:21 +02:00
|
|
|
}
|