All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.couchbase.lite.FileLogger Maven / Gradle / Ivy

//
// Copyright (c) 2020, 2018 Couchbase, Inc All rights reserved.
//
// Licensed 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 com.couchbase.lite;

import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;

import java.io.File;

import com.couchbase.lite.internal.core.C4Log;
import com.couchbase.lite.internal.core.CBLVersion;
import com.couchbase.lite.internal.support.Log;


/**
 * A logger for writing to a file in the application's storage so
 * that log messages can persist durably after the application has
 * stopped or encountered a problem.  Each log level is written to
 * a separate file.
 * Threading policy: This class is certain to be used from multiple
 * threads.  As long as it is thread safe, the various race conditions
 * are unlikely and the penalties very small.  "Volatile" ensures
 * the thread safety and the several races are tolerable.
 */
public final class FileLogger implements Logger {
    @Nullable
    private volatile LogFileConfiguration config;
    @Nullable
    private volatile String initializedPath;
    @NonNull
    private volatile LogLevel logLevel;

    // The singleton instance is available from Database.log.getFile()
    FileLogger() {
        logLevel = LogLevel.NONE;
        reset();
    }

    @Override
    public void log(@NonNull LogLevel level, @NonNull LogDomain domain, @NonNull String message) {
        if ((config == null) || (level.compareTo(logLevel) < 0)) { return; }
        C4Log.log(Log.getC4DomainForLoggingDomain(domain), level.getValue(), message);
    }

    @NonNull
    @Override
    public LogLevel getLevel() { return logLevel; }

    /**
     * Sets the overall logging level that will be written to the logging files.
     *
     * @param level The maximum level to include in the logs
     */
    public void setLevel(@NonNull LogLevel level) {
        if (config == null) {
            throw new IllegalStateException(Log.lookupStandardMessage("CannotSetLogLevel"));
        }

        if (logLevel == level) { return; }
        logLevel = level;

        if (!initLog()) { C4Log.setBinaryFileLevel(level.getValue()); }

        if (level == LogLevel.NONE) { Log.warn(); }
    }

    /**
     * Gets the configuration currently in use by the file logger.
     * Note that once a configuration has been installed in a logger,
     * the configuration is read-only and can no longer be modified.
     * An attempt to modify the configuration returned by this method will cause an exception.
     *
     * @return The configuration currently in use
     */
    @Nullable
    public LogFileConfiguration getConfig() { return config; }

    /**
     * Sets the configuration for use by the file logger.
     *
     * @param newConfig The configuration to use
     */
    public void setConfig(@Nullable LogFileConfiguration newConfig) {
        if (config == newConfig) { return; }

        if (newConfig == null) {
            config = null;
            Log.warn();
            return;
        }

        final File logDir = new File(newConfig.getDirectory());
        String errMsg = null;
        if (!logDir.exists()) {
            if (!logDir.mkdirs()) { errMsg = "Cannot create log directory: " + logDir.getAbsolutePath(); }
        }
        else {
            if (!logDir.isDirectory()) { errMsg = logDir.getAbsolutePath() + " is not a directory"; }
            else if (!logDir.canWrite()) { errMsg = logDir.getAbsolutePath() + " is not writable"; }
        }

        if (errMsg != null) {
            Log.w(LogDomain.DATABASE, errMsg);
            return;
        }

        config = newConfig.readOnlyCopy();

        initLog();
    }

    @VisibleForTesting
    void reset() {
        config = null;
        initializedPath = null;
        logLevel = LogLevel.NONE;
    }

    private boolean initLog() {
        final LogLevel level = logLevel;
        final LogFileConfiguration cfg = config;

        if ((cfg == null) || (level == LogLevel.NONE)) { return false; }

        final String logDirPath = cfg.getDirectory();
        if (logDirPath.equals(initializedPath)) { return false; }
        initializedPath = logDirPath;

        C4Log.writeToBinaryFile(
            logDirPath,
            level.getValue(),
            cfg.getMaxRotateCount(),
            cfg.getMaxSize(),
            cfg.usesPlaintext(),
            CBLVersion.getVersionInfo());

        return true;
    }
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy