diff options
Diffstat (limited to 'vespalog/src/main/java/com/yahoo/log/VespaLogHandler.java')
-rw-r--r-- | vespalog/src/main/java/com/yahoo/log/VespaLogHandler.java | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/vespalog/src/main/java/com/yahoo/log/VespaLogHandler.java b/vespalog/src/main/java/com/yahoo/log/VespaLogHandler.java new file mode 100644 index 00000000000..26208340132 --- /dev/null +++ b/vespalog/src/main/java/com/yahoo/log/VespaLogHandler.java @@ -0,0 +1,136 @@ +// Copyright 2016 Yahoo Inc. 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.logging.Level; +import java.util.logging.LogRecord; +import java.util.logging.StreamHandler; + +/** + * @author Bjorn Borud + * @author arnej27959 + */ +class VespaLogHandler extends StreamHandler { + + 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: + * + * <DL> + * <DT> <code>fd:<number></code> + * <DD> Log to specified file descriptor number. Only "fd:2" + * is supported. + * + * <DT> <code>file:<filename></code> + * <DD> Log to specified file in append mode + * </DL> + */ + public 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. + */ + public synchronized void publish (LogRecord record) { + Level level = record.getLevel(); + String component = record.getLoggerName(); + + LevelController ctrl = getLevelControl(component); + 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(); + } + + public LevelController getLevelControl(String component) { + return repo.getLevelController(component); + } + + /** + * Initalize 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 */ + public 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(); + } +} |