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

com.yahoo.log.VespaLogHandler 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.UnsupportedEncodingException;
import java.util.Map;
import java.util.function.Function;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.StreamHandler;

import static java.util.Map.entry;
import static java.util.logging.Level.FINE;
import static java.util.logging.Level.INFO;

/**
 * @author Bjorn Borud
 * @author arnej27959
 */
@SuppressWarnings("deprecation")
class VespaLogHandler extends StreamHandler {

    // Reduce log level for some loggers
    private static final Function INFO_TO_FINE = level -> level == INFO ? FINE : level;
    private static final Map> loggersWithAlteredLogLevel = Map.ofEntries(
            entry("com.yahoo.vespa.spifly.repackaged.spifly.BaseActivator", INFO_TO_FINE),
            entry("org.eclipse.jetty.server.Server", INFO_TO_FINE),
            entry("org.eclipse.jetty.server.handler.ContextHandler", INFO_TO_FINE),
            entry("org.eclipse.jetty.server.AbstractConnector", INFO_TO_FINE),
            entry("org.eclipse.jetty.util.HostPort", __ -> FINE)
    );

    private final LogTarget logTarget;
    private final String serviceName;
    private final String appPrefix;
    private final LevelControllerRepo repo;
    private final RejectFilter logRejectFilter;

    /**
     * Construct handler which logs to specified logTarget.  The logTarget
     * may be of the following formats:
     *
     * 
*
fd:<number> *
Log to specified file descriptor number. Only "fd:2" * is supported. * *
file:<filename> *
Log to specified file in append mode *
*/ VespaLogHandler(LogTarget logTarget, LevelControllerRepo levelControllerRepo, String serviceName, String applicationPrefix) { this.logTarget = logTarget; this.serviceName = serviceName; this.appPrefix = applicationPrefix; this.repo = levelControllerRepo; this.logRejectFilter = RejectFilter.createDefaultRejectFilter(); initialize(); } /** * Publish a log record into the Vespa log target. */ @Override public synchronized void publish(LogRecord record) { String loggerName = record.getLoggerName(); Level level = possiblyReduceLogLevel(loggerName, record.getLevel()); LevelController ctrl = getLevelControl(loggerName); if (!ctrl.shouldLog(level)) { return; } if (logRejectFilter.shouldReject(record.getMessage())) { return; } try { // provokes rotation of target setOutputStream(logTarget.open()); } catch (RuntimeException e) { LogRecord r = new LogRecord(Level.SEVERE, "Unable to open file target"); r.setThrown(e); emergencyLog(r); setOutputStream(System.err); } super.publish(record); flush(); closeFileTarget(); } private static Level possiblyReduceLogLevel(String loggerName, Level level) { if (loggerName == null) return level; var levelMapper = loggersWithAlteredLogLevel.get(loggerName); return levelMapper == null ? level : levelMapper.apply(level); } LevelController getLevelControl(String component) { return repo.getLevelController(component); } /** * Initialize the handler. The main invariant is that * outputStream is always set to something valid when this method * returns. */ private void initialize () { try { setFormatter(new VespaFormatter(serviceName, appPrefix)); setLevel(LogLevel.ALL); setEncoding("UTF-8"); // System.err.println("initialize vespa logging, default level: "+defaultLogLevel); setOutputStream(logTarget.open()); } catch (UnsupportedEncodingException uee) { LogRecord r = new LogRecord(Level.SEVERE, "Unable to set log encoding to UTF-8"); r.setThrown(uee); emergencyLog(r); } catch (RuntimeException e) { LogRecord r = new LogRecord(Level.SEVERE, "Unable to open file target"); r.setThrown(e); emergencyLog(r); setOutputStream(System.err); } } /** Closes the target log file, if there is one */ synchronized void closeFileTarget() { try { logTarget.close(); } catch (RuntimeException e) { LogRecord r = new LogRecord(Level.WARNING, "Unable to close log"); r.setThrown(e); emergencyLog(r); } } /** * If the logging system experiences problems we can't be expected * to log it through normal channels, so we have an emergency log * method which just uses STDERR for formatting the log messages. * (Which might be right, and might be wrong). * * @param record The log record to be logged */ private void emergencyLog(LogRecord record) { record.setLoggerName(VespaLogHandler.class.getName()); System.err.println(getFormatter().format(record)); } public void cleanup() { repo.close(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy