+++ /dev/null
-/*
- * Copyright [2005] [University Corporation for Advanced Internet Development, Inc.]
- *
- * 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 edu.internet2.middleware.shibboleth.log;
-
-import java.io.IOException;
-
-import org.apache.log4j.ConsoleAppender;
-import org.apache.log4j.FileAppender;
-import org.apache.log4j.Level;
-import org.apache.log4j.Logger;
-import org.apache.log4j.PatternLayout;
-import org.apache.log4j.PropertyConfigurator;
-import org.apache.log4j.xml.DOMConfigurator;
-import org.w3c.dom.Element;
-import org.w3c.dom.NamedNodeMap;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-import edu.internet2.middleware.shibboleth.common.ShibResource;
-import edu.internet2.middleware.shibboleth.common.ShibbolethConfigurationException;
-import edu.internet2.middleware.shibboleth.idp.IdPConfig;
-
-/**
- * A helper class for configuring the the IdP transaction log, general system log, and any logs specified in a Log4J
- * configuration file.
- * <p>
- * The IdP transaction log with the name <code>Shibboleth-TRANSACTION</code> and should be used to track an
- * individuals path through the IdP. It's default logging level is <code>INFO</code>.
- * <p>
- * The general system log logs messages from any class in either the <code>edu.internet2.middleware.shibboleth</code>
- * package or the <code>org.opensaml</code> package. It's default logging level is <code>WARN</code>
- * <p>
- * All logs are configured through information found in the IdP XML configuration file.
- *
- * @author Chad La Joie
- */
-public class LoggingInitializer {
-
- /**
- * The log file extension
- */
- private static String logFileExtension = ".log";
-
- /**
- * Log message layout pattern for the transaction log
- */
- private static String txLogLayoutPattern = "%d{ISO8601} %m%n";
-
- /**
- * Date pattern used at the end of the transaction log filename
- */
- private static String txLogAppenderDatePattern = "'.'yyyy-MM-dd";
-
- /**
- * Log message layout pattern for the general system log
- */
- private static String sysLogLayoutPattern = "%d{ISO8601} %-5p %-41X{serviceId} - %m%n";
-
- /**
- * Date pattern used at the end of the general system log filename
- */
- private static String sysLogAppenderDatePattern = "'.'yyyy-MM-dd";
-
- /**
- * Initializes the Log4J logging framework.
- *
- * @param configuration
- * logging configuration element from the IdP XML configuration file
- * @throws ShibbolethConfigurationException
- * thrown if there is a problem configuring the logs
- */
- public static void initializeLogging(Element configuration) throws ShibbolethConfigurationException {
-
- NodeList txLogElems = configuration.getElementsByTagNameNS(IdPConfig.configNameSpace, "TransactionLog");
- if (txLogElems.getLength() > 0) {
- if (txLogElems.getLength() > 1) {
- System.err.println("WARNING: More than one TransactionLog element detected in IdP logging "
- + "configuration, only the first one will be used.");
- }
- Element txLogConfig = (Element) txLogElems.item(0);
- configureTransactionLog(txLogConfig);
- } else {
- configureTransactionLog();
- }
-
- NodeList sysLogElems = configuration.getElementsByTagNameNS(IdPConfig.configNameSpace, "ErrorLog");
- if (sysLogElems.getLength() > 0) {
- if (sysLogElems.getLength() > 1) {
- System.err.println("WARNING: More than one ErrorLog element detected in IdP logging configuration, "
- + "only the first one will be used.");
- }
- Element sysLogConfig = (Element) sysLogElems.item(0);
- configureSystemLog(sysLogConfig);
- } else {
- configureSystemLog();
- }
-
- NodeList log4jElems = configuration.getElementsByTagNameNS(IdPConfig.configNameSpace, "Log4JConfig");
- if (log4jElems.getLength() > 0) {
- if (log4jElems.getLength() > 1) {
- System.err.println("WARNING: More than one Log4JConfig element detected in IdP logging configuration, "
- + "only the first one will be used.");
- }
- Element log4jConfig = (Element) log4jElems.item(0);
- configureLog4J(log4jConfig);
- }
- }
-
- /**
- * Initialize the logs for the Shibboleth-TRANSACTION log, edu.internet2.middleware.shibboleth, and org.opensaml
- * logs. Output is directed to the standard out with the the transaction log at INFO level and the remainder at
- * warn.
- */
- public static void initializeLogging() {
-
- configureTransactionLog();
- configureSystemLog();
- }
-
- /**
- * Configured the transaction log to log to the console at INFO level.
- */
- private static void configureTransactionLog() {
-
- ConsoleAppender appender = new ConsoleAppender(new PatternLayout(txLogLayoutPattern),
- ConsoleAppender.SYSTEM_OUT);
- Logger log = Logger.getLogger("Shibboleth-TRANSACTION");
- log.setAdditivity(false); // do not want parent's messages
- log.setLevel(Level.INFO);
- log.addAppender(appender);
- }
-
- /**
- * Configures the transaction log.
- *
- * @param configuration
- * the TransactionLog element from the IdP XML logging configuration
- * @throws ShibbolethConfigurationException
- * thrown if there is a problem configuring the logs
- */
- private static void configureTransactionLog(Element configuration) throws ShibbolethConfigurationException {
-
- NamedNodeMap attributes = configuration.getAttributes();
-
- String location = attributes.getNamedItem("location").getNodeValue();
- if (location == null) { throw new ShibbolethConfigurationException(
- "No log file location attribute specified in TransactionLog element"); }
-
- FileAppender appender = null;
- try {
- String logPath = new ShibResource(location, LoggingInitializer.class).getFile().getCanonicalPath();
- appender = createRollingFileAppender(txLogLayoutPattern, logPath, txLogAppenderDatePattern);
- appender.setName("shibboleth-transaction");
- } catch (Exception e) {
- throw new ShibbolethConfigurationException("<TransactionLog location=\"" + location
- + "\">: error creating DailyRollingFileAppender: " + e);
- }
-
- Level level = Level.INFO;
- if (attributes.getNamedItem("level") != null) {
- level = Level.toLevel(attributes.getNamedItem("level").getNodeValue());
- }
-
- Logger log = Logger.getLogger("Shibboleth-TRANSACTION");
- log.setAdditivity(false); // do not want parent's messages
- log.setLevel(level);
- log.addAppender(appender);
- }
-
- /**
- * Configures the standard system log to log messages from edu.internet2.middleware.shibboleth and org.opensaml to
- * the console at WARN level.
- */
- private static void configureSystemLog() {
-
- ConsoleAppender appender = new ConsoleAppender(new PatternLayout(sysLogLayoutPattern),
- ConsoleAppender.SYSTEM_OUT);
- Logger shibLog = Logger.getLogger("edu.internet2.middleware.shibboleth");
- shibLog.setLevel(Level.WARN);
- shibLog.addAppender(appender);
-
- Logger openSAMLLog = Logger.getLogger("org.opensaml");
- openSAMLLog.setLevel(Level.WARN);
- openSAMLLog.addAppender(appender);
- }
-
- /**
- * Configures the system-wide IdP log.
- *
- * @param configuration
- * the ErrorLog element from the IdP XML logging configuration
- * @throws ShibbolethConfigurationException
- * thrown if there is a problem configuring the logs
- */
- private static void configureSystemLog(Element configuration) throws ShibbolethConfigurationException {
-
- NamedNodeMap attributes = configuration.getAttributes();
-
- String location = attributes.getNamedItem("location").getNodeValue();
- if (location == null) { throw new ShibbolethConfigurationException(
- "No log file location attribute specified in ErrorLog element"); }
-
- FileAppender appender = null;
- try {
- String logPath = new ShibResource(location, LoggingInitializer.class).getFile().getCanonicalPath();
- appender = createRollingFileAppender(sysLogLayoutPattern, logPath, sysLogAppenderDatePattern);
- appender.setName("shibboleth-error");
- } catch (Exception e) { // catch any exception
- throw new ShibbolethConfigurationException("<ErrorLog location=\"" + location
- + "\">: error creating DailyRollingFileAppender: " + e);
- }
-
- Level level = Level.WARN;
- if (attributes.getNamedItem("level") != null) {
- level = Level.toLevel(attributes.getNamedItem("level").getNodeValue());
- }
-
- Logger shibLog = Logger.getLogger("edu.internet2.middleware.shibboleth");
- shibLog.setLevel(level);
- shibLog.addAppender(appender);
-
- Logger openSAMLLog = Logger.getLogger("org.opensaml");
- openSAMLLog.setLevel(level);
- openSAMLLog.addAppender(appender);
- }
-
- /**
- * Creates a rolling file appender. If the given log file ends with .* the characters after the .
- * will be treated as the logs extension. If there is no . in the log file path a default extension
- * of "log" will be used. When the log file is rolled the resulting file name is "logfile"."date"."extension".
- *
- * @param messagePattern patterns for the log messages
- * @param logFile the log file
- * @param datePattern the date pattern to roll the file one
- *
- * @return a rolling file appender
- *
- * @throws IOException thrown if the appender can not create the initial log file
- */
- private static FileAppender createRollingFileAppender(String messagePattern, String logFile, String datePattern) throws IOException {
- PatternLayout messageLayout = new PatternLayout(messagePattern);
-
- int fileExtDelimIndex = logFile.lastIndexOf(".");
- if(fileExtDelimIndex <= 0) {
- return new RollingFileAppender(messageLayout, logFile, datePattern, ".log");
- }else {
- String filePath = logFile.substring(0, fileExtDelimIndex);
- String fileExtension = logFile.substring(fileExtDelimIndex);
-
- return new RollingFileAppender(messageLayout, filePath, datePattern, fileExtension);
- }
- }
-
- /**
- * Configures Log4J by way of a Log4J specific configuration file.
- *
- * @param configuration
- * the Log4JConfig element from the IdP XML logging configuration
- * @throws ShibbolethConfigurationException
- * thrown if there is a problem configuring the logs
- */
- private static void configureLog4J(Element configuration) throws ShibbolethConfigurationException {
-
- NamedNodeMap attributes = configuration.getAttributes();
-
- String location = attributes.getNamedItem("location").getNodeValue();
- if (location == null) { throw new ShibbolethConfigurationException(
- "No configuration file location attribute specified in Log4JConfig element"); }
-
- String type = null;
- Node typeNode = attributes.getNamedItem("type");
- if (typeNode != null) {
- type = typeNode.getNodeValue();
- }
-
- ShibResource log4jConfig;
- try {
- log4jConfig = new ShibResource(location);
- if (type == null || "properties".equals(type)) {
- PropertyConfigurator.configure(log4jConfig.getURL());
- } else if ("xml".equals(type)) {
- DOMConfigurator.configure(log4jConfig.getURL());
- } else {
- throw new ShibbolethConfigurationException(
- "<Log4JConfig (type) attribute must be one of \"xml\" or \"properties\".");
- }
- } catch (IOException e) {
- throw new ShibbolethConfigurationException("<Log4JConfig location=\"" + location + "\">: not a valid URL: "
- + e);
- }
-
- }
-}
\ No newline at end of file
+++ /dev/null
-/*
- * This class borrows extensively from the Log4J DailyRollingFileAppender
- * written by Eirik Lygre and Ceki Gulcu and copyrighted to the Apache Foundation
- * under the Apache 2 License (http://apache.org/licenses/LICENSE-2.0).
- */
-
-package edu.internet2.middleware.shibboleth.log;
-
-import java.io.File;
-import java.io.IOException;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.GregorianCalendar;
-import java.util.Locale;
-import java.util.TimeZone;
-
-import org.apache.log4j.FileAppender;
-import org.apache.log4j.Layout;
-import org.apache.log4j.helpers.LogLog;
-import org.apache.log4j.spi.LoggingEvent;
-
-/**
- * A minor refactoring of Log4J's DailyRollingFileAppender. The log4j appender does not provide an easy mechanism for
- * having a file name of name.date.extension, instead it wants to do name.extension.date which on some platforms can be
- * a pain. This appender is meant to handle this case.
- *
- * The file appender will create a file called filename.extension, then it will roll over the files to
- * filename.date.extension. The default date pattern is "'.'yyyy-MM-dd" (i.e. daily roll over) and the default file
- * extnsion is '.log'.
- *
- * @author Chad La Joie
- */
-public class RollingFileAppender
- extends FileAppender {
-
- // The code assumes that the following constants are in a increasing
- // sequence.
- static final int TOP_OF_TROUBLE = -1;
-
- static final int TOP_OF_MINUTE = 0;
-
- static final int TOP_OF_HOUR = 1;
-
- static final int HALF_DAY = 2;
-
- static final int TOP_OF_DAY = 3;
-
- static final int TOP_OF_WEEK = 4;
-
- static final int TOP_OF_MONTH = 5;
-
- /**
- * The date pattern. By default, the pattern is set to "'.'yyyy-MM-dd" meaning daily rollover.
- */
- private String datePattern = "'-'yyyy-MM-dd";
-
- /**
- * The log file will be renamed to the value of the scheduledFilename variable when the next interval is entered.
- * For example, if the rollover period is one hour, the log file will be renamed to the value of "scheduledFilename"
- * at the beginning of the next hour.
- *
- * The precise time when a rollover occurs depends on logging activity.
- */
- private String scheduledFilename;
-
- /**
- * The next time we estimate a rollover should occur.
- */
- private long nextCheck = System.currentTimeMillis() - 1;
-
- /**
- * Current date
- */
- private Date now = new Date();
-
- /**
- * The date pattern
- */
- private SimpleDateFormat sdf;
-
- /**
- * Calendar for determing roll over information
- */
- private RollingCalendar rc = new RollingCalendar();
-
- /**
- * How often to check for roll over
- */
- int checkPeriod = TOP_OF_TROUBLE;
-
- /**
- * The gmtTimeZone is used only in computeCheckPeriod() method.
- */
- static final TimeZone gmtTimeZone = TimeZone.getTimeZone("GMT");
-
- /**
- * The file extension
- */
- private String fileExtension = ".log";
-
- /**
- * The file name without the date or extension components.
- */
- private String simpleFileName;
-
- /**
- * Default constructor
- */
- public RollingFileAppender() {
-
- }
-
- /**
- * Constructor.
- *
- * @param layout the log entry layout pattern
- * @param filename the file name
- * @param datePattern the date pattern used to determine rolling behavior
- * @param fileExtension the file extension to post-pend to log file name
- *
- * @throws IOException thrown if the file can not be created
- */
- public RollingFileAppender(Layout layout, String filename, String datePattern, String fileExtension)
- throws IOException {
- super(layout, filename + fileExtension, true);
- simpleFileName = filename;
- setDatePattern(datePattern);
- setFileExtension(fileExtension);
- activateOptions();
- }
-
- /**
- * Gets the extension post-pended to the file name.
- *
- * @return the log file's extension
- */
- public String getFileExtension() {
- return fileExtension;
- }
-
- /**
- * Sets the extension post-pended to the file name.
- *
- * @param extension the log file's extension
- */
- public void setFileExtension(String extension) {
- fileExtension = extension;
- }
-
- /**
- * The <b>DatePattern</b> takes a string in the same format as expected by {@link SimpleDateFormat}. This options
- * determines the rollover schedule.
- *
- * @param pattern the rollover date pattern
- */
- public void setDatePattern(String pattern) {
- datePattern = pattern;
- }
-
- /**
- * Returns the value of the <b>DatePattern</b> option.
- *
- * @return the rollover date pattern
- */
- public String getDatePattern() {
- return datePattern;
- }
-
- public void activateOptions() {
- super.activateOptions();
- if (datePattern != null && fileName != null) {
- now.setTime(System.currentTimeMillis());
- sdf = new SimpleDateFormat(datePattern);
- int type = computeCheckPeriod();
- printPeriodicity(type);
- rc.setType(type);
- File file = new File(fileName);
- scheduledFilename = simpleFileName + sdf.format(new Date(file.lastModified())) + fileExtension;
-
- } else {
- LogLog.error("Either File or DatePattern options are not set for appender [" + name + "].");
- }
- }
-
- void printPeriodicity(int type) {
- switch (type) {
- case TOP_OF_MINUTE:
- LogLog.debug("Appender [" + name + "] to be rolled every minute.");
- break;
- case TOP_OF_HOUR:
- LogLog.debug("Appender [" + name + "] to be rolled on top of every hour.");
- break;
- case HALF_DAY:
- LogLog.debug("Appender [" + name + "] to be rolled at midday and midnight.");
- break;
- case TOP_OF_DAY:
- LogLog.debug("Appender [" + name + "] to be rolled at midnight.");
- break;
- case TOP_OF_WEEK:
- LogLog.debug("Appender [" + name + "] to be rolled at start of week.");
- break;
- case TOP_OF_MONTH:
- LogLog.debug("Appender [" + name + "] to be rolled at start of every month.");
- break;
- default:
- LogLog.warn("Unknown periodicity for appender [" + name + "].");
- }
- }
-
- // This method computes the roll over period by looping over the
- // periods, starting with the shortest, and stopping when the r0 is
- // different from from r1, where r0 is the epoch formatted according
- // the datePattern (supplied by the user) and r1 is the
- // epoch+nextMillis(i) formatted according to datePattern. All date
- // formatting is done in GMT and not local format because the test
- // logic is based on comparisons relative to 1970-01-01 00:00:00
- // GMT (the epoch).
-
- int computeCheckPeriod() {
- RollingCalendar rollingCalendar = new RollingCalendar(gmtTimeZone, Locale.ENGLISH);
- Date epoch = new Date(0);
- if (datePattern != null) {
- for (int i = TOP_OF_MINUTE; i <= TOP_OF_MONTH; i++) {
- SimpleDateFormat simpleDateFormat = new SimpleDateFormat(datePattern);
- simpleDateFormat.setTimeZone(gmtTimeZone); // do all date formatting in GMT
- String r0 = simpleDateFormat.format(epoch);
- rollingCalendar.setType(i);
- Date next = new Date(rollingCalendar.getNextCheckMillis(epoch));
- String r1 = simpleDateFormat.format(next);
- if (r0 != null && r1 != null && !r0.equals(r1)) {
- return i;
- }
- }
- }
- return TOP_OF_TROUBLE; // Deliberately head for trouble...
- }
-
- /**
- * Rollover the current file to a new file.
- */
- void rollOver() {
-
- /* Compute filename, but only if datePattern is specified */
- if (datePattern == null) {
- errorHandler.error("Missing DatePattern option in rollOver().");
- return;
- }
-
- String datedFilename = simpleFileName + sdf.format(now) + fileExtension;
- // It is too early to roll over because we are still within the
- // bounds of the current interval. Rollover will occur once the
- // next interval is reached.
- if (scheduledFilename.equals(datedFilename)) {
- return;
- }
-
- // close current file, and rename it to datedFilename
- this.closeFile();
-
- File target = new File(scheduledFilename);
- if (target.exists()) {
- target.delete();
- }
-
- File file = new File(fileName);
- boolean result = file.renameTo(target);
- if (result) {
- LogLog.debug(fileName + " -> " + scheduledFilename);
- } else {
- LogLog.error("Failed to rename [" + fileName + "] to [" + scheduledFilename + "].");
- }
-
- try {
- // This will also close the file. This is OK since multiple
- // close operations are safe.
- this.setFile(fileName, false, this.bufferedIO, this.bufferSize);
- }
- catch (IOException e) {
- errorHandler.error("setFile(" + fileName + ", false) call failed.");
- }
- scheduledFilename = datedFilename;
- }
-
- /**
- * This method differentiates DailyRollingFileAppender from its super class.
- *
- * <p>
- * Before actually logging, this method will check whether it is time to do a rollover. If it is, it will schedule
- * the next rollover time and then rollover.
- */
- protected void subAppend(LoggingEvent event) {
- long n = System.currentTimeMillis();
- if (n >= nextCheck) {
- now.setTime(n);
- nextCheck = rc.getNextCheckMillis(now);
- rollOver();
- }
- super.subAppend(event);
- }
-}
-
-/**
- * RollingCalendar is a helper class to DailyRollingFileAppender. Given a periodicity type and the current time, it
- * computes the start of the next interval.
- */
-class RollingCalendar
- extends GregorianCalendar {
-
- /**
- * Serial Number
- */
- private static final long serialVersionUID = -1818276930015758128L;
-
- int type = RollingFileAppender.TOP_OF_TROUBLE;
-
- RollingCalendar() {
- super();
- }
-
- RollingCalendar(TimeZone tz, Locale locale) {
- super(tz, locale);
- }
-
- void setType(int type) {
- this.type = type;
- }
-
- public long getNextCheckMillis(Date now) {
- return getNextCheckDate(now).getTime();
- }
-
- public Date getNextCheckDate(Date now) {
- this.setTime(now);
-
- switch (type) {
- case RollingFileAppender.TOP_OF_MINUTE:
- this.set(Calendar.SECOND, 0);
- this.set(Calendar.MILLISECOND, 0);
- this.add(Calendar.MINUTE, 1);
- break;
- case RollingFileAppender.TOP_OF_HOUR:
- this.set(Calendar.MINUTE, 0);
- this.set(Calendar.SECOND, 0);
- this.set(Calendar.MILLISECOND, 0);
- this.add(Calendar.HOUR_OF_DAY, 1);
- break;
- case RollingFileAppender.HALF_DAY:
- this.set(Calendar.MINUTE, 0);
- this.set(Calendar.SECOND, 0);
- this.set(Calendar.MILLISECOND, 0);
- int hour = get(Calendar.HOUR_OF_DAY);
- if (hour < 12) {
- this.set(Calendar.HOUR_OF_DAY, 12);
- } else {
- this.set(Calendar.HOUR_OF_DAY, 0);
- this.add(Calendar.DAY_OF_MONTH, 1);
- }
- break;
- case RollingFileAppender.TOP_OF_DAY:
- this.set(Calendar.HOUR_OF_DAY, 0);
- this.set(Calendar.MINUTE, 0);
- this.set(Calendar.SECOND, 0);
- this.set(Calendar.MILLISECOND, 0);
- this.add(Calendar.DATE, 1);
- break;
- case RollingFileAppender.TOP_OF_WEEK:
- this.set(Calendar.DAY_OF_WEEK, getFirstDayOfWeek());
- this.set(Calendar.HOUR_OF_DAY, 0);
- this.set(Calendar.SECOND, 0);
- this.set(Calendar.MILLISECOND, 0);
- this.add(Calendar.WEEK_OF_YEAR, 1);
- break;
- case RollingFileAppender.TOP_OF_MONTH:
- this.set(Calendar.DATE, 1);
- this.set(Calendar.HOUR_OF_DAY, 0);
- this.set(Calendar.SECOND, 0);
- this.set(Calendar.MILLISECOND, 0);
- this.add(Calendar.MONTH, 1);
- break;
- default:
- throw new IllegalStateException("Unknown periodicity type.");
- }
- return getTime();
- }
-}
\ No newline at end of file