/* * Copyright 2013 * * 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 org.openntf.domino.logging; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.security.AccessControlException; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.Properties; import java.util.TimeZone; import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.LogManager; import java.util.logging.Logger; import org.openntf.domino.utils.DominoUtils; // TODO: Auto-generated Javadoc /** * The Class LogUtils. * * @author withersp */ /** * @author withersp * */ public class LogUtils { /** * Initializes a SimpleDateFormat for use if UTC is not enabled * * @since org.openntf.domino 1.0.0 */ private static ThreadLocal<SimpleDateFormat> ISO_LOCAL = new ThreadLocal<SimpleDateFormat>() { @Override protected SimpleDateFormat initialValue() { return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); } }; /** * Initializes a SimpleDateFormat for use if UTC is enabled * * @since org.openntf.domino 1.0.0 */ private static ThreadLocal<SimpleDateFormat> ISO_UTC_LOCAL = new ThreadLocal<SimpleDateFormat>() { @Override protected SimpleDateFormat initialValue() { SimpleDateFormat ISO8601_UTC = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); //$NON-NLS-1$; TimeZone tz = TimeZone.getTimeZone("UTC"); ISO8601_UTC.setTimeZone(tz); return ISO8601_UTC; } }; /** * Instantiates a new log utils. * * @since org.openntf.domino 1.0.0 */ public LogUtils() { } /** * Parses logging.properties and replaces any instances of <notesdata> with the path for the domino\data folder * * @param is * InputStream comprising logging.properties * @return InputStream replaced content from logging.properties * @since org.openntf.domino 1.0.0 */ private static InputStream parsePropertiesStream(final InputStream is) { // System.out.println("Parsing properties stream..."); Properties props = new Properties(); try { props.load(is); String datapath = org.openntf.domino.utils.Factory.getDataPath() + "/"; for (Object key : props.keySet()) { if (key instanceof String) { String keyName = (String) key; String value = props.getProperty(keyName); if (value.indexOf("<notesdata>") > -1) { String result = value.replace("<notesdata>", datapath); // System.out.println("Found notesdata variable in properties value for " + keyName); // System.out.println("Replacing with " + datapath + " to result in " + result); props.put(keyName, result); } // value.replace("%notesprogram%", Factory.getProgramPath() + java.io.File.pathSeparator); } } ByteArrayOutputStream os = new ByteArrayOutputStream(); props.store(os, ""); InputStream result = new ByteArrayInputStream(os.toByteArray()); return result; } catch (Exception e) { e.printStackTrace(); return is; } } /** * Retrieves default logging properties file from this package as InputStream. <br/> * Called by getLogConfigFile(int, String) if no file passed to it or file not found. * * @return InputStream of logging configuration using logging.properties in org.openntf.domino.logging * @since org.openntf.domino 1.0.0 */ public static InputStream getDefaultLogConfigFile() { try { InputStream raw = LogUtils.class.getResourceAsStream("logging.properties"); return parsePropertiesStream(raw); } catch (Throwable e) { System.out.println("SEVERE: Error getting default log config file"); return null; } } /** * Retrieves a log file or, if that cannot be retrieved, the default log file. * * @param fileType * int passed to switch statement in DominoUtils.getDominoProps. <br/> * See DominoUtils.getDominoProps for options available. * @param filePath * String path of file to be used. Can be literal or relative to <data> directory * @return InputStream content of properties file * @since org.openntf.domino 1.0.0 */ public static InputStream getLogConfigFile(final int fileType, final String filePath) { InputStream is = null; try { if ("".equals(filePath)) { return getDefaultLogConfigFile(); } else { is = parsePropertiesStream(DominoUtils.getDominoProps(fileType, filePath)); if (null == is) { is = getDefaultLogConfigFile(); } return is; } } catch (Throwable e) { System.out.println("SEVERE: Error getting log config file: " + filePath + " (" + Integer.toString(fileType) + ")"); return null; } } /** * Converts a date to an ISO8601 string. * * @param value * The date. * @param utc * Boolean, whether to format the time in UTC or the local time zone. * @return The ISO8601 string. * @since org.openntf.domino 1.0.0 */ public static String dateToString(final Date value, final boolean utc) { String result = null; if (utc) { result = ISO_UTC_LOCAL.get().format(value); } else { result = ISO_LOCAL.get().format(value); } return result; } /** * Initialise a logger based on a configuration file. * * @param relative * boolean whether filepath is relative to <data> folder * @param filePath * String of filepath for logging properties file, or empty string to load the default org.openntf.domino logger * @since org.openntf.domino 1.0.0 */ static public void loadLoggerConfig(final boolean relative, final String filePath) { System.out.println("Loading Logger config..."); try { AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { @Override public Object run() throws Exception { LogManager manager = LogManager.getLogManager(); if ("".equals(filePath)) { InputStream is = getDefaultLogConfigFile(); if (is != null) { manager.readConfiguration(is); } } else { InputStream is = null; if (relative) { is = getLogConfigFile(3, filePath); } else { is = getLogConfigFile(2, filePath); } manager.readConfiguration(is); } return null; } }); System.out.println("Completed logger config."); } catch (AccessControlException e) { e.printStackTrace(); } catch (PrivilegedActionException e) { e.printStackTrace(); } } /** * Updates a specified Logger with settings passed in. Pass in an ArrayList of Handlers, whether or not to use the parent handler, and a * new security level. Options for security level are: * * <ul> * <li>Level.SEVERE</li> * <li>Level.WARNING</li> * <li>Level.INFO</li> * <li>Level.CONFIG</li> * <li>Level.FINE</li> * <li>Level.FINER</li> * <li>Level.FINEST</li> * </ul> * * @param logName * The name of the logger to modify * @param handlers * an array of Handler objects to apply to the logger. Any pre-defined handlers will be removed. To pass in existing * handlers, just use myLogger.getHandlers(). * @param useParentHandler * boolean of whether or not to use parent handlers * @param newSeverityLevel * the new severity level * @return success or failure in updating the logger * @since org.openntf.domino 1.0.0 */ public static boolean setupLoggerEx(final String logName, final ArrayList<Handler> handlers, final boolean useParentHandler, final Level newSeverityLevel) { try { boolean result = (Boolean) AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { @Override public Object run() throws Exception { Logger loggerToModify = getLogger(logName); for (Handler currHandlers : loggerToModify.getHandlers()) { loggerToModify.removeHandler(currHandlers); } for (Handler newHandler : handlers) { newHandler.setLevel(newSeverityLevel); loggerToModify.addHandler(newHandler); } loggerToModify.setUseParentHandlers(useParentHandler); if (null != newSeverityLevel) { loggerToModify.setLevel(newSeverityLevel); } return true; } }); return result; } catch (AccessControlException e) { e.printStackTrace(); } catch (PrivilegedActionException e) { e.printStackTrace(); } return false; } /** * Check whether you can change a logger property. XPages and Websphere security is draconian and doesn't allow modifying loggers. One * option is set java.policy to grant all, but that's not good. This will see whether they work or not. <br/> * <br/> * In case of failure, you can either use another, non-standard logging mechanism like OpenLog, or log using com.ibm.xsp.domino and * Level.SEVERE - that's the only level logged by that logger. * * @param log_ * Logger to try and change * @return success or failure. * @since org.openntf.domino 1.0.0 */ public static boolean hasAccessException(final Logger log_) { try { log_.setLevel(log_.getLevel()); return false; } catch (AccessControlException e) { return true; } catch (Throwable t) { return true; } } /** * Gets a logger from the LogManager. * * @param logName * name of the logger * @return The Logger object * @since org.openntf.domino 1.0.0 */ public static Logger getLogger(final String logName) { LogManager manager = LogManager.getLogManager(); Logger loggerToModify = manager.getLogger(logName); return loggerToModify; } }