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

com.yahoo.log.LogSetup Maven / Gradle / Ivy

There is a newer version: 8.442.54
Show newest version
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.log;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Timer;
import java.util.logging.FileHandler;
import java.util.logging.Filter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.LogRecord;
import java.util.logging.Logger;

/**
 * Sets up Vespa logging. Call a setup method to set up this.
 *
 * @author  Bjorn Borud
 * @author arnej27959
 */
public class LogSetup {

    private static final Timer taskRunner = new Timer(true);

    static Timer getTaskRunner() { return taskRunner; }

    /** The log handler used by this */
    private static VespaLogHandler logHandler;

    private static ZooKeeperFilter zooKeeperFilter = null;

    /** Clear all handlers registered in java.util.logging framework */
    public static void clearHandlers () {
        Enumeration names = LogManager.getLogManager().getLoggerNames();
        while (names.hasMoreElements()) {
            String name = names.nextElement();
            Logger logger = Logger.getLogger(name);

            Handler[] handlers = logger.getHandlers();
            for (Handler handler : handlers) {
                logger.removeHandler(handler);
            }
        }
    }

    private static boolean isInitialized = false;

    /**
     * Every Vespa application should call initVespaLogging exactly
     * one time.  This should be done from the main() method or from a
     * static initializer in the main class.  The library will pick up
     * the environment variables usually set by the Vespa
     * config-sentinel (VESPA_LOG_LEVEL, VESPA_LOG_TARGET,
     * VESPA_SERVICE_NAME, VESPA_LOG_CONTROL_DIR) but it's possible to
     * override these by setting system properties before calling
     * initVespaLogging.  This may be useful for unit testing etc:
     * 
* System.setProperty("vespa.log.level", "all") *
* System.setProperty("vespa.log.target", "file:foo.log") *
* System.setProperty("vespa.service.name", "my.name") *
* System.setProperty("vespa.log.control.dir", ".") *
* System.setProperty("vespa.log.control.file", "my.logcontrol") *
* vespa.log.control.file is used if it's set, otherwise it's * vespa.log.control.dir + "/" + vespa.service.name + ".logcontrol" * if both of those variables are set, otherwise there will be no * runtime log control. * * @param programName the name of the program that is running; * this is added as a prefix to the logger name to form the * "component" part of the log message. (Usually the logger name * is the name of the class that logs something, so the * programName should be kept short and simple.) **/ public static void initVespaLogging(String programName) { if (isInitialized) { System.err.println("WARNING: initVespaLogging called twice"); } isInitialized = true; // prefer Java system properties String logLevel = System.getProperty("vespa.log.level"); String logTarget = System.getProperty("vespa.log.target"); String logService = System.getProperty("vespa.service.name"); String logControlDir = System.getProperty("vespa.log.control.dir"); String logControlFile = System.getProperty("vespa.log.control.file"); if (programName == null || programName.equals("")) { throw new RuntimeException("invalid programName: " + programName); } // then try environment values if (logTarget == null) logTarget = System.getenv("VESPA_LOG_TARGET"); if (logService == null) logService = System.getenv("VESPA_SERVICE_NAME"); if (logControlDir == null) logControlDir = System.getenv("VESPA_LOG_CONTROL_DIR"); if (logControlFile == null) logControlFile = System.getenv("VESPA_LOG_CONTROL_FILE"); if (logLevel == null) logLevel = System.getenv("VESPA_LOG_LEVEL"); // then hardcoded defaults if (logTarget == null) logTarget = "fd:2"; if (logLevel == null) logLevel = "all -debug -spam"; if (logControlFile == null && logControlDir != null && logService != null && !logService.equals("") && !logService.equals("-")) { logControlFile = logControlDir + "/" + logService + ".logcontrol"; } // for backwards compatibility - XXX should be removed if (logService == null) logService = System.getProperty("config.id"); if (logService == null) logService = "-"; System.setProperty("vespa.service.name", logService); System.setProperty("vespa.program.name", programName); try { initInternal(logTarget, logService, logControlFile, programName, logLevel); } catch (FileNotFoundException e) { throw new RuntimeException("Unable to initialize logging", e); } } private static LogTarget getLogTargetFromString(String target) throws FileNotFoundException { if ("fd:2".equals(target)) { return new StderrLogTarget(); } else if ("fd:1".equals(target)) { return new StdoutLogTarget(); } else if (target.startsWith("file:")) { return new FileLogTarget(new File(target.substring(5))); } throw new IllegalArgumentException("Target '" + target + "' is not a valid target"); } private static void initInternal(String target, String service, String logCtlFn, String app, String lev) throws FileNotFoundException { clearHandlers(); if (app != null && app.length() > 64) app = app.substring(0, 63); if (logHandler != null) { logHandler.cleanup(); Logger.getLogger("").removeHandler(logHandler); } Logger.getLogger("").setLevel(Level.ALL); logHandler = new VespaLogHandler(getLogTargetFromString(target), new VespaLevelControllerRepo(logCtlFn, lev, app), service, app); String zookeeperLogFile = System.getProperty("zookeeper_log_file_prefix"); if (zookeeperLogFile != null) { zooKeeperFilter = new ZooKeeperFilter(zookeeperLogFile); logHandler.setFilter(zooKeeperFilter); } Logger.getLogger("").addHandler(logHandler); } static VespaLogHandler getLogHandler() { return logHandler; } /** perform cleanup */ public static void cleanup() { if (zooKeeperFilter != null) zooKeeperFilter.close(); } /** * Class that has an isLoggable methods that handles log records that * start with "org.apache.zookeeper." or "org.apache.curator" * (writing them to a log file with the prefix specified in the system property * zookeeper_log_file_prefix) and returning false. * For other log records, isLoggable returns true */ static class ZooKeeperFilter implements Filter { private static final int FILE_SIZE = 10*1024*1024; // Max 10 Mb per log file private static final int maxFilesCount = 10; // Keep at most 10 log files private FileHandler fileHandler; ZooKeeperFilter(String logFilePrefix) { String logFilePattern = logFilePrefix + ".%g.log"; try { fileHandler = new FileHandler(logFilePattern, FILE_SIZE, maxFilesCount, true); fileHandler.setFormatter(new VespaFormatter()); } catch (IOException e) { System.out.println("Not able to create " + logFilePattern); fileHandler = null; } } /** * Return true if loggable (ordinary log record), returns false if this filter * logs the log record itself * * @param record a #{@link LogRecord} * @return true if loggable, false otherwise */ @Override public boolean isLoggable(LogRecord record) { if (record.getLoggerName() == null) return true; if (!record.getLoggerName().startsWith("org.apache.zookeeper.") && !record.getLoggerName().startsWith("org.apache.curator")) { return true; } fileHandler.publish(record); return false; } public void close() { fileHandler.close(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy