| /******************************************************************************* |
| * Copyright (c) 2004, 2017 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.osgi.internal.log; |
| |
| import java.io.BufferedWriter; |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.InputStreamReader; |
| import java.io.OutputStream; |
| import java.io.OutputStreamWriter; |
| import java.io.PrintWriter; |
| import java.io.Reader; |
| import java.io.StringWriter; |
| import java.io.Writer; |
| import java.lang.reflect.InvocationTargetException; |
| import java.nio.charset.StandardCharsets; |
| import java.util.Calendar; |
| import java.util.Date; |
| import java.util.Map; |
| import org.eclipse.core.runtime.adaptor.EclipseStarter; |
| import org.eclipse.equinox.log.ExtendedLogEntry; |
| import org.eclipse.equinox.log.LogFilter; |
| import org.eclipse.equinox.log.SynchronousLogListener; |
| import org.eclipse.osgi.framework.log.FrameworkLogEntry; |
| import org.eclipse.osgi.internal.framework.EquinoxConfiguration; |
| import org.osgi.framework.Bundle; |
| import org.osgi.framework.BundleException; |
| import org.osgi.service.log.LogEntry; |
| import org.osgi.service.log.LogLevel; |
| import org.osgi.service.log.LogService; |
| import org.osgi.service.log.admin.LoggerAdmin; |
| import org.osgi.service.log.admin.LoggerContext; |
| |
| class EquinoxLogWriter implements SynchronousLogListener, LogFilter { |
| private static final String PASSWORD = "-password"; //$NON-NLS-1$ |
| /** The session tag */ |
| private static final String SESSION = "!SESSION"; //$NON-NLS-1$ |
| /** The entry tag */ |
| private static final String ENTRY = "!ENTRY"; //$NON-NLS-1$ |
| /** The sub-entry tag */ |
| private static final String SUBENTRY = "!SUBENTRY"; //$NON-NLS-1$ |
| /** The message tag */ |
| private static final String MESSAGE = "!MESSAGE"; //$NON-NLS-1$ |
| /** The stacktrace tag */ |
| private static final String STACK = "!STACK"; //$NON-NLS-1$ |
| |
| /** The line separator used in the log output */ |
| private static final String LINE_SEPARATOR; |
| |
| static { |
| String s = System.getProperty("line.separator"); //$NON-NLS-1$ |
| LINE_SEPARATOR = s == null ? "\n" : s; //$NON-NLS-1$ |
| } |
| |
| //Constants for rotating log file |
| /** The default size a log file can grow before it is rotated */ |
| private static final int DEFAULT_LOG_SIZE = 1000; |
| /** The default number of backup log files */ |
| private static final int DEFAULT_LOG_FILES = 10; |
| /** The minimum size limit for log rotation */ |
| private static final int LOG_SIZE_MIN = 10; |
| |
| /** The system property used to specify the log level */ |
| private static final String PROP_LOG_LEVEL = "eclipse.log.level"; //$NON-NLS-1$ |
| /** The system property used to specify size a log file can grow before it is rotated */ |
| private static final String PROP_LOG_SIZE_MAX = "eclipse.log.size.max"; //$NON-NLS-1$ |
| /** The system property used to specify the maximim number of backup log files to use */ |
| private static final String PROP_LOG_FILE_MAX = "eclipse.log.backup.max"; //$NON-NLS-1$ |
| /** The extension used for log files */ |
| private static final String LOG_EXT = ".log"; //$NON-NLS-1$ |
| /** The extension markup to use for backup log files*/ |
| private static final String BACKUP_MARK = ".bak_"; //$NON-NLS-1$ |
| |
| /** The system property used to specify command line args should be omitted from the log */ |
| private static final String PROP_LOG_INCLUDE_COMMAND_LINE = "eclipse.log.include.commandline"; //$NON-NLS-1$ |
| /** Indicates if the console messages should be printed to the console (System.out) */ |
| private boolean consoleLog = false; |
| /** Indicates if the next log message is part of a new session */ |
| private boolean newSession = true; |
| /** |
| * The File object to store messages. This value may be null. |
| */ |
| private File outFile; |
| |
| /** |
| * The Writer to log messages to. |
| */ |
| private Writer writer; |
| |
| private final String loggerName; |
| private final boolean enabled; |
| private final EquinoxConfiguration environmentInfo; |
| |
| int maxLogSize = DEFAULT_LOG_SIZE; // The value is in KB. |
| int maxLogFiles = DEFAULT_LOG_FILES; |
| int backupIdx = 0; |
| |
| private int logLevel = FrameworkLogEntry.OK; |
| private boolean includeCommandLine = true; |
| |
| private LoggerAdmin loggerAdmin = null; |
| |
| /** |
| * Constructs an EclipseLog which uses the specified File to log messages to |
| * @param outFile a file to log messages to |
| */ |
| public EquinoxLogWriter(File outFile, String loggerName, boolean enabled, EquinoxConfiguration environmentInfo) { |
| this.outFile = outFile; |
| this.writer = null; |
| this.loggerName = loggerName; |
| this.enabled = enabled; |
| this.environmentInfo = environmentInfo; |
| readLogProperties(); |
| } |
| |
| /** |
| * Constructs an EclipseLog which uses the specified Writer to log messages to |
| * @param writer a writer to log messages to |
| */ |
| public EquinoxLogWriter(Writer writer, String loggerName, boolean enabled, EquinoxConfiguration environmentInfo) { |
| if (writer == null) |
| // log to System.err by default |
| this.writer = logForErrorStream(); |
| else |
| this.writer = writer; |
| this.loggerName = loggerName; |
| this.enabled = enabled; |
| this.environmentInfo = environmentInfo; |
| } |
| |
| private Throwable getRoot(Throwable t) { |
| Throwable root = null; |
| if (t instanceof BundleException) |
| root = ((BundleException) t).getNestedException(); |
| if (t instanceof InvocationTargetException) |
| root = ((InvocationTargetException) t).getTargetException(); |
| // skip inner InvocationTargetExceptions and BundleExceptions |
| if (root instanceof InvocationTargetException || root instanceof BundleException) { |
| Throwable deeplyNested = getRoot(root); |
| if (deeplyNested != null) |
| // if we have something more specific, use it, otherwise keep what we have |
| root = deeplyNested; |
| } |
| return root; |
| } |
| |
| /** |
| * Helper method for writing out argument arrays. |
| * @param header the header |
| * @param args the list of arguments |
| */ |
| private void writeArgs(String header, String[] args) throws IOException { |
| if (args == null || args.length == 0) |
| return; |
| write(header); |
| for (int i = 0; i < args.length; i++) { |
| //mask out the password argument for security |
| if (i > 0 && PASSWORD.equals(args[i - 1])) |
| write(" (omitted)"); //$NON-NLS-1$ |
| else |
| write(" " + args[i]); //$NON-NLS-1$ |
| } |
| writeln(); |
| } |
| |
| /** |
| * Returns the session timestamp. This is the time the platform was started |
| * @return the session timestamp |
| */ |
| private String getSessionTimestamp() { |
| // Main should have set the session start-up timestamp so return that. |
| // Return the "now" time if not available. |
| String ts = environmentInfo.getConfiguration("eclipse.startTime"); //$NON-NLS-1$ |
| if (ts != null) { |
| try { |
| return getDate(new Date(Long.parseLong(ts))); |
| } catch (NumberFormatException e) { |
| // fall through and use the timestamp from right now |
| } |
| } |
| return getDate(new Date()); |
| } |
| |
| /** |
| * Writes the session |
| * @throws IOException if an error occurs writing to the log |
| */ |
| private void writeSession() throws IOException { |
| write(SESSION); |
| writeSpace(); |
| String date = getSessionTimestamp(); |
| write(date); |
| writeSpace(); |
| for (int i = SESSION.length() + date.length(); i < 78; i++) { |
| write("-"); //$NON-NLS-1$ |
| } |
| writeln(); |
| // Write out certain values found in System.getProperties() |
| try { |
| String key = "eclipse.buildId"; //$NON-NLS-1$ |
| String value = environmentInfo.getConfiguration(key, "unknown"); //$NON-NLS-1$ |
| writeln(key + "=" + value); //$NON-NLS-1$ |
| |
| key = "java.fullversion"; //$NON-NLS-1$ |
| value = System.getProperty(key); |
| if (value == null) { |
| key = "java.version"; //$NON-NLS-1$ |
| value = System.getProperty(key); |
| writeln(key + "=" + value); //$NON-NLS-1$ |
| key = "java.vendor"; //$NON-NLS-1$ |
| value = System.getProperty(key); |
| writeln(key + "=" + value); //$NON-NLS-1$ |
| } else { |
| writeln(key + "=" + value); //$NON-NLS-1$ |
| } |
| } catch (Exception e) { |
| // If we're not allowed to get the values of these properties |
| // then just skip over them. |
| } |
| // The Bootloader has some information that we might be interested in. |
| write("BootLoader constants: OS=" + environmentInfo.getOS()); //$NON-NLS-1$ |
| write(", ARCH=" + environmentInfo.getOSArch()); //$NON-NLS-1$ |
| write(", WS=" + environmentInfo.getWS()); //$NON-NLS-1$ |
| writeln(", NL=" + environmentInfo.getNL()); //$NON-NLS-1$ |
| // Add the command-line arguments used to invoke the platform |
| // XXX: this includes runtime-private arguments - should we do that? |
| if (includeCommandLine) { |
| writeArgs("Framework arguments: ", environmentInfo.getNonFrameworkArgs()); //$NON-NLS-1$ |
| writeArgs("Command-line arguments: ", environmentInfo.getCommandLineArgs()); //$NON-NLS-1$ |
| } |
| } |
| |
| public void close() { |
| try { |
| if (writer != null) { |
| Writer tmpWriter = writer; |
| writer = null; |
| tmpWriter.close(); |
| } |
| } catch (IOException e) { |
| e.printStackTrace(); |
| } |
| } |
| |
| /** |
| * If a File is used to log messages to then the File opened and a Writer is created |
| * to log messages to. |
| */ |
| private void openFile() { |
| if (writer == null) { |
| if (outFile != null) { |
| try { |
| writer = logForStream(ExtendedLogServiceFactory.secureAction.getFileOutputStream(outFile, true)); |
| } catch (IOException e) { |
| writer = logForErrorStream(); |
| } |
| } else { |
| writer = logForErrorStream(); |
| } |
| } |
| } |
| |
| /** |
| * If a File is used to log messages to then the writer is closed. |
| */ |
| private void closeFile() { |
| if (outFile != null) { |
| if (writer != null) { |
| try { |
| writer.close(); |
| } catch (IOException e) { |
| // we cannot log here; just print the stacktrace. |
| e.printStackTrace(); |
| } |
| writer = null; |
| } |
| } |
| } |
| |
| private synchronized void log(FrameworkLogEntry logEntry) { |
| if (logEntry == null) |
| return; |
| if (!isLoggable(logEntry.getSeverity())) |
| return; |
| try { |
| checkLogFileSize(); |
| openFile(); |
| if (newSession) { |
| writeSession(); |
| newSession = false; |
| } |
| writeLog(0, logEntry); |
| writer.flush(); |
| } catch (Exception e) { |
| // any exceptions during logging should be caught |
| System.err.println("An exception occurred while writing to the platform log:");//$NON-NLS-1$ |
| e.printStackTrace(System.err); |
| System.err.println("Logging to the console instead.");//$NON-NLS-1$ |
| //we failed to write, so dump log entry to console instead |
| try { |
| writer = logForErrorStream(); |
| writeLog(0, logEntry); |
| writer.flush(); |
| } catch (Exception e2) { |
| System.err.println("An exception occurred while logging to the console:");//$NON-NLS-1$ |
| e2.printStackTrace(System.err); |
| } |
| } finally { |
| closeFile(); |
| } |
| } |
| |
| public synchronized void setWriter(Writer newWriter, boolean append) { |
| setOutput(null, newWriter, append); |
| } |
| |
| /** |
| * @throws IOException |
| */ |
| public synchronized void setFile(File newFile, boolean append) throws IOException { |
| if (newFile != null && !newFile.equals(this.outFile)) { |
| // If it's a new file, then reset. |
| readLogProperties(); |
| backupIdx = 0; |
| } |
| setOutput(newFile, null, append); |
| environmentInfo.setConfiguration(EclipseStarter.PROP_LOGFILE, newFile == null ? "" : newFile.getAbsolutePath()); //$NON-NLS-1$ |
| } |
| |
| synchronized void setLoggerAdmin(LoggerAdmin loggerAdmin) { |
| this.loggerAdmin = loggerAdmin; |
| applyLogLevel(); |
| } |
| |
| public synchronized File getFile() { |
| return outFile; |
| } |
| |
| public void setConsoleLog(boolean consoleLog) { |
| this.consoleLog = consoleLog; |
| } |
| |
| private void setOutput(File newOutFile, Writer newWriter, boolean append) { |
| if (newOutFile == null || !newOutFile.equals(this.outFile)) { |
| if (this.writer != null) { |
| try { |
| this.writer.close(); |
| } catch (IOException e) { |
| e.printStackTrace(); |
| } |
| this.writer = null; |
| } |
| // Append old outFile to newWriter. We only attempt to do this |
| // if the current Writer is backed by a File and this is not |
| // a new session. |
| File oldOutFile = this.outFile; |
| this.outFile = newOutFile; |
| this.writer = newWriter; |
| boolean copyFailed = false; |
| if (append && oldOutFile != null && oldOutFile.isFile()) { |
| Reader fileIn = null; |
| try { |
| openFile(); |
| fileIn = new InputStreamReader(ExtendedLogServiceFactory.secureAction.getFileInputStream(oldOutFile), "UTF-8"); //$NON-NLS-1$ |
| copyReader(fileIn, this.writer); |
| } catch (IOException e) { |
| copyFailed = true; |
| e.printStackTrace(); |
| } finally { |
| if (fileIn != null) { |
| try { |
| fileIn.close(); |
| } catch (IOException e) { |
| e.printStackTrace(); |
| } |
| // delete the old file if copying didn't fail |
| if (!copyFailed) |
| oldOutFile.delete(); |
| } |
| closeFile(); |
| } |
| } |
| } |
| } |
| |
| private void copyReader(Reader reader, Writer aWriter) throws IOException { |
| char buffer[] = new char[1024]; |
| int count; |
| while ((count = reader.read(buffer, 0, buffer.length)) > 0) { |
| aWriter.write(buffer, 0, count); |
| } |
| } |
| |
| /** |
| * Returns a date string using the correct format for the log. |
| * @param date the Date to format |
| * @return a date string. |
| */ |
| private String getDate(Date date) { |
| Calendar c = Calendar.getInstance(); |
| c.setTime(date); |
| StringBuilder sb = new StringBuilder(); |
| appendPaddedInt(c.get(Calendar.YEAR), 4, sb).append('-'); |
| appendPaddedInt(c.get(Calendar.MONTH) + 1, 2, sb).append('-'); |
| appendPaddedInt(c.get(Calendar.DAY_OF_MONTH), 2, sb).append(' '); |
| appendPaddedInt(c.get(Calendar.HOUR_OF_DAY), 2, sb).append(':'); |
| appendPaddedInt(c.get(Calendar.MINUTE), 2, sb).append(':'); |
| appendPaddedInt(c.get(Calendar.SECOND), 2, sb).append('.'); |
| appendPaddedInt(c.get(Calendar.MILLISECOND), 3, sb); |
| return sb.toString(); |
| } |
| |
| private StringBuilder appendPaddedInt(int value, int pad, StringBuilder buffer) { |
| pad = pad - 1; |
| if (pad == 0) |
| return buffer.append(Integer.toString(value)); |
| int padding = (int) Math.pow(10, pad); |
| if (value >= padding) |
| return buffer.append(Integer.toString(value)); |
| while (padding > value && padding > 1) { |
| buffer.append('0'); |
| padding = padding / 10; |
| } |
| buffer.append(value); |
| return buffer; |
| } |
| |
| /** |
| * Returns a stacktrace string using the correct format for the log |
| * @param t the Throwable to get the stacktrace for |
| * @return a stacktrace string |
| */ |
| private String getStackTrace(Throwable t) { |
| if (t == null) |
| return null; |
| |
| StringWriter sw = new StringWriter(); |
| PrintWriter pw = new PrintWriter(sw); |
| |
| t.printStackTrace(pw); |
| // ensure the root exception is fully logged |
| Throwable root = getRoot(t); |
| if (root != null) { |
| pw.println("Root exception:"); //$NON-NLS-1$ |
| root.printStackTrace(pw); |
| } |
| return sw.toString(); |
| } |
| |
| /** |
| * Returns a Writer for the given OutputStream |
| * @param output an OutputStream to use for the Writer |
| * @return a Writer for the given OutputStream |
| */ |
| private Writer logForStream(OutputStream output) { |
| return new BufferedWriter(new OutputStreamWriter(output, StandardCharsets.UTF_8)); |
| } |
| |
| /** |
| * Always use the default encoding for System.err |
| */ |
| private Writer logForErrorStream() { |
| return new BufferedWriter(new OutputStreamWriter(System.err)); |
| } |
| |
| /** |
| * Writes the log entry to the log using the specified depth. A depth value of 0 |
| * indicates that the log entry is the root entry. Any value greater than 0 indicates |
| * a sub-entry. |
| * @param depth the depth of th entry |
| * @param entry the entry to log |
| * @throws IOException if any error occurs writing to the log |
| */ |
| private void writeLog(int depth, FrameworkLogEntry entry) throws IOException { |
| writeEntry(depth, entry); |
| writeMessage(entry); |
| writeStack(entry); |
| |
| FrameworkLogEntry[] children = entry.getChildren(); |
| if (children != null) { |
| for (FrameworkLogEntry child : children) { |
| writeLog(depth + 1, child); |
| } |
| } |
| } |
| |
| /** |
| * Writes the ENTRY or SUBENTRY header for an entry. A depth value of 0 |
| * indicates that the log entry is the root entry. Any value greater than 0 indicates |
| * a sub-entry. |
| * @param depth the depth of th entry |
| * @param entry the entry to write the header for |
| * @throws IOException if any error occurs writing to the log |
| */ |
| private void writeEntry(int depth, FrameworkLogEntry entry) throws IOException { |
| if (depth == 0) { |
| writeln(); // write a blank line before all !ENTRY tags bug #64406 |
| write(ENTRY); |
| } else { |
| write(SUBENTRY); |
| writeSpace(); |
| write(Integer.toString(depth)); |
| } |
| writeSpace(); |
| write(entry.getEntry()); |
| writeSpace(); |
| write(Integer.toString(entry.getSeverity())); |
| writeSpace(); |
| write(Integer.toString(entry.getBundleCode())); |
| writeSpace(); |
| write(getDate(new Date())); |
| writeln(); |
| } |
| |
| /** |
| * Writes the MESSAGE header to the log for the given entry. |
| * @param entry the entry to write the message for |
| * @throws IOException if any error occurs writing to the log |
| */ |
| private void writeMessage(FrameworkLogEntry entry) throws IOException { |
| write(MESSAGE); |
| writeSpace(); |
| writeln(entry.getMessage()); |
| } |
| |
| /** |
| * Writes the STACK header to the log for the given entry. |
| * @param entry the entry to write the stacktrace for |
| * @throws IOException if any error occurs writing to the log |
| */ |
| private void writeStack(FrameworkLogEntry entry) throws IOException { |
| Throwable t = entry.getThrowable(); |
| if (t != null) { |
| String stack = getStackTrace(t); |
| write(STACK); |
| writeSpace(); |
| write(Integer.toString(entry.getStackCode())); |
| writeln(); |
| write(stack); |
| } |
| } |
| |
| /** |
| * Writes the given message to the log. |
| * @param message the message |
| * @throws IOException if any error occurs writing to the log |
| */ |
| private void write(String message) throws IOException { |
| if (message != null) { |
| writer.write(message); |
| if (consoleLog) |
| System.out.print(message); |
| } |
| } |
| |
| /** |
| * Writes the given message to the log and a newline. |
| * @param s the message |
| * @throws IOException if any error occurs writing to the log |
| */ |
| private void writeln(String s) throws IOException { |
| write(s); |
| writeln(); |
| } |
| |
| /** |
| * Writes a newline log. |
| * @throws IOException if any error occurs writing to the log |
| */ |
| private void writeln() throws IOException { |
| write(LINE_SEPARATOR); |
| } |
| |
| /** |
| * Writes a space to the log. |
| * @throws IOException if any error occurs writing to the log |
| */ |
| private void writeSpace() throws IOException { |
| write(" "); //$NON-NLS-1$ |
| } |
| |
| /** |
| * Checks the log file size. If the log file size reaches the limit then the log |
| * is rotated |
| * @return false if an error occured trying to rotate the log |
| */ |
| private boolean checkLogFileSize() { |
| if (maxLogSize == 0) |
| return true; // no size limitation. |
| |
| boolean isBackupOK = true; |
| if (outFile != null) { |
| if ((ExtendedLogServiceFactory.secureAction.length(outFile) >> 10) > maxLogSize) { // Use KB as file size unit. |
| String logFilename = outFile.getAbsolutePath(); |
| |
| // Delete old backup file that will be replaced. |
| String backupFilename = ""; //$NON-NLS-1$ |
| if (logFilename.toLowerCase().endsWith(LOG_EXT)) { |
| backupFilename = logFilename.substring(0, logFilename.length() - LOG_EXT.length()) + BACKUP_MARK + backupIdx + LOG_EXT; |
| } else { |
| backupFilename = logFilename + BACKUP_MARK + backupIdx; |
| } |
| File backupFile = new File(backupFilename); |
| if (backupFile.exists()) { |
| if (!backupFile.delete()) { |
| System.err.println("Error when trying to delete old log file: " + backupFile.getName());//$NON-NLS-1$ |
| if (backupFile.renameTo(new File(backupFile.getAbsolutePath() + System.currentTimeMillis()))) { |
| System.err.println("So we rename it to filename: " + backupFile.getName()); //$NON-NLS-1$ |
| } else { |
| System.err.println("And we also cannot rename it!"); //$NON-NLS-1$ |
| isBackupOK = false; |
| } |
| } |
| } |
| |
| // Rename current log file to backup one. |
| boolean isRenameOK = outFile.renameTo(backupFile); |
| if (!isRenameOK) { |
| System.err.println("Error when trying to rename log file to backup one."); //$NON-NLS-1$ |
| isBackupOK = false; |
| } |
| File newFile = new File(logFilename); |
| setOutput(newFile, null, false); |
| |
| // Write a new SESSION header to new log file. |
| openFile(); |
| try { |
| writeSession(); |
| writeln(); |
| writeln("This is a continuation of log file " + backupFile.getAbsolutePath());//$NON-NLS-1$ |
| writeln("Created Time: " + getDate(new Date(System.currentTimeMillis()))); //$NON-NLS-1$ |
| writer.flush(); |
| } catch (IOException ioe) { |
| ioe.printStackTrace(System.err); |
| } |
| closeFile(); |
| backupIdx = (++backupIdx) % maxLogFiles; |
| } |
| } |
| return isBackupOK; |
| } |
| |
| /** |
| * Reads the PROP_LOG_SIZE_MAX and PROP_LOG_FILE_MAX properties. |
| */ |
| private void readLogProperties() { |
| String newMaxLogSize = environmentInfo.getConfiguration(PROP_LOG_SIZE_MAX); |
| if (newMaxLogSize != null) { |
| maxLogSize = Integer.parseInt(newMaxLogSize); |
| if (maxLogSize != 0 && maxLogSize < LOG_SIZE_MIN) { |
| // If the value is '0', then it means no size limitation. |
| // Also, make sure no inappropriate(too small) assigned value. |
| maxLogSize = LOG_SIZE_MIN; |
| } |
| } |
| |
| String newMaxLogFiles = environmentInfo.getConfiguration(PROP_LOG_FILE_MAX); |
| if (newMaxLogFiles != null) { |
| maxLogFiles = Integer.parseInt(newMaxLogFiles); |
| if (maxLogFiles < 1) { |
| // Make sure no invalid assigned value. (at least >= 1) |
| maxLogFiles = DEFAULT_LOG_FILES; |
| } |
| } |
| |
| String newLogLevel = environmentInfo.getConfiguration(PROP_LOG_LEVEL); |
| if (newLogLevel != null) { |
| if (newLogLevel.equals("ERROR")) //$NON-NLS-1$ |
| logLevel = FrameworkLogEntry.ERROR; |
| else if (newLogLevel.equals("WARNING")) //$NON-NLS-1$ |
| logLevel = FrameworkLogEntry.ERROR | FrameworkLogEntry.WARNING; |
| else if (newLogLevel.equals("INFO")) //$NON-NLS-1$ |
| logLevel = FrameworkLogEntry.INFO | FrameworkLogEntry.ERROR | FrameworkLogEntry.WARNING | FrameworkLogEntry.CANCEL; |
| else |
| logLevel = FrameworkLogEntry.OK; // OK (0) means log everything |
| } |
| |
| includeCommandLine = "true".equals(environmentInfo.getConfiguration(PROP_LOG_INCLUDE_COMMAND_LINE, "true")); //$NON-NLS-1$//$NON-NLS-2$ |
| applyLogLevel(); |
| } |
| |
| void applyLogLevel() { |
| if (loggerAdmin == null) { |
| return; |
| } |
| LoggerContext rootContext = loggerAdmin.getLoggerContext(null); |
| Map<String, LogLevel> rootLevels = rootContext.getLogLevels(); |
| rootLevels.put(loggerName, getLogLevel()); |
| rootContext.setLogLevels(rootLevels); |
| } |
| |
| private LogLevel getLogLevel() { |
| if (logLevel == 0) { |
| return LogLevel.TRACE; |
| } |
| if ((logLevel & FrameworkLogEntry.INFO) != 0) { |
| return LogLevel.INFO; |
| } |
| if ((logLevel & FrameworkLogEntry.WARNING) != 0) { |
| return LogLevel.WARN; |
| } |
| if ((logLevel & FrameworkLogEntry.ERROR) != 0) { |
| return LogLevel.ERROR; |
| } |
| // not sure what to do here; it seems it would be an error |
| return LogLevel.AUDIT; |
| } |
| |
| /** |
| * Determines if the log entry should be logged based on log level. |
| */ |
| private boolean isLoggable(int fwkEntrySeverity) { |
| if (logLevel == 0) |
| return true; |
| return (fwkEntrySeverity & logLevel) != 0; |
| } |
| |
| @SuppressWarnings("deprecation") |
| @Override |
| public boolean isLoggable(Bundle bundle, String loggableName, int loggableLevel) { |
| if (!enabled) |
| return false; |
| if (loggerName.equals(loggableName)) |
| return isLoggable(convertSeverity(loggableLevel)); |
| if (EquinoxLogServices.PERF_LOGGER_NAME.equals(loggableName)) |
| // we don't want to do anything with performance logger unless |
| // this is the performance logger (check done above). |
| return false; |
| if (!EquinoxLogServices.EQUINOX_LOGGER_NAME.equals(loggerName)) |
| // only the equinox log writer should pay attention to other logs |
| return false; |
| // for now only log errors; probably need this to be configurable |
| return loggableLevel == LogService.LOG_ERROR; |
| } |
| |
| @SuppressWarnings("deprecation") |
| @Override |
| public void logged(LogEntry entry) { |
| if (!(entry instanceof ExtendedLogEntry)) |
| // TODO this should never happen |
| return; |
| ExtendedLogEntry extended = (ExtendedLogEntry) entry; |
| Object context = extended.getContext(); |
| if (context instanceof FrameworkLogEntry) { |
| log((FrameworkLogEntry) context); |
| return; |
| } |
| // OK we are now in a case where someone logged a normal entry to the real LogService |
| log(new FrameworkLogEntry(getFwkEntryTag(entry), convertSeverity(entry.getLevel()), 0, entry.getMessage(), 0, entry.getException(), null)); |
| } |
| |
| private static String getFwkEntryTag(LogEntry entry) { |
| Bundle b = entry.getBundle(); |
| if (b != null && b.getSymbolicName() != null) |
| return b.getSymbolicName(); |
| return "unknown"; //$NON-NLS-1$ |
| } |
| |
| @SuppressWarnings("deprecation") |
| private static int convertSeverity(int entryLevel) { |
| switch (entryLevel) { |
| case LogService.LOG_ERROR : |
| return FrameworkLogEntry.ERROR; |
| case LogService.LOG_WARNING : |
| return FrameworkLogEntry.WARNING; |
| case LogService.LOG_INFO : |
| return FrameworkLogEntry.INFO; |
| case LogService.LOG_DEBUG : |
| return FrameworkLogEntry.OK; |
| default : |
| return 32; // unknown |
| } |
| } |
| |
| public String getLoggerName() { |
| return loggerName; |
| } |
| } |