    001    /*
    002     * Licensed to the Apache Software Foundation (ASF) under one or more
    003     * contributor license agreements. See the NOTICE file distributed with
    004     * this work for additional information regarding copyright ownership.
    005     * The ASF licenses this file to You under the Apache license, Version 2.0
    006     * (the "License"); you may not use this file except in compliance with
    007     * the License. You may obtain a copy of the License at
    008     *
    009     *      http://www.apache.org/licenses/LICENSE-2.0
    010     *
    011     * Unless required by applicable law or agreed to in writing, software
    012     * distributed under the License is distributed on an "AS IS" BASIS,
    013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014     * See the license for the specific language governing permissions and
    015     * limitations under the license.
    016     */
    017    package org.apache.logging.log4j.core.appender.rolling;
    018
    019    import java.lang.reflect.Method;
    020
    021    import org.apache.logging.log4j.core.LogEvent;
    022    import org.apache.logging.log4j.core.config.plugins.Plugin;
    023    import org.apache.logging.log4j.core.config.plugins.PluginFactory;
    024    import org.apache.logging.log4j.core.util.Loader;
    025    import org.apache.logging.log4j.status.StatusLogger;
    026
    027    /**
    028     * Triggers a rollover on every restart. The target file's timestamp is compared with the JVM start time
    029     * and if it is older isTriggeringEvent will return true. After isTriggeringEvent has been called it will
    030     * always return false.
    031     */
    032    @Plugin(name = "OnStartupTriggeringPolicy", category = "Core", printObject = true)
    033    public class OnStartupTriggeringPolicy implements TriggeringPolicy {
    034        private static long JVM_START_TIME = initStartTime();
    035
    036        private boolean evaluated = false;
    037        private RollingFileManager manager;
    038
    039        /**
    040         * Provide the RollingFileManager to the policy.
    041         * @param manager The RollingFileManager.
    042         */
    043        @Override
    044        public void initialize(final RollingFileManager manager) {
    045            this.manager = manager;
    046            if (JVM_START_TIME == 0) {
    047                evaluated = true;
    048            }
    049        }
    050
    051        /**
    052         * Returns the result of {@code ManagementFactory.getRuntimeMXBean().getStartTime()},
    053         * or the current system time if JMX is not available.
    054         */
    055        private static long initStartTime() {
    056            // LOG4J2-379:
    057            // We'd like to call ManagementFactory.getRuntimeMXBean().getStartTime(),
    058            // but Google App Engine throws a java.lang.NoClassDefFoundError
    059            // "java.lang.management.ManagementFactory is a restricted class".
    060            // The reflection is necessary because without it, Google App Engine
    061            // will refuse to initialize this class.
    062            try {
    063                final Class<?> factoryClass = Loader.loadSystemClass("java.lang.management.ManagementFactory");
    064                final Method getRuntimeMXBean = factoryClass.getMethod("getRuntimeMXBean");
    065                final Object runtimeMXBean = getRuntimeMXBean.invoke(null);
    066
    067                final Class<?> runtimeMXBeanClass = Loader.loadSystemClass("java.lang.management.RuntimeMXBean");
    068                final Method getStartTime = runtimeMXBeanClass.getMethod("getStartTime");
    069                final Long result = (Long) getStartTime.invoke(runtimeMXBean);
    070
    071                return result.longValue();
    072            } catch (final Throwable t) {
    073                StatusLogger.getLogger().error("Unable to call ManagementFactory.getRuntimeMXBean().getStartTime(), " //
    074                        + "using system time for OnStartupTriggeringPolicy", t);
    075                // We have little option but to declare "now" as the beginning of time.
    076                return System.currentTimeMillis();
    077            }
    078        }
    079
    080        /**
    081         * Determine if a rollover should be triggered.
    082         * @param event   A reference to the current event.
    083         * @return true if the target file's timestamp is older than the JVM start time.
    084         */
    085        @Override
    086        public boolean isTriggeringEvent(final LogEvent event) {
    087            if (evaluated) {
    088                return false;
    089            }
    090            evaluated = true;
    091            return manager.getFileTime() < JVM_START_TIME;
    092        }
    093
    094        @Override
    095        public String toString() {
    096            return "OnStartupTriggeringPolicy";
    097        }
    098
    099        @PluginFactory
    100        public static OnStartupTriggeringPolicy createPolicy() {
    101            return new OnStartupTriggeringPolicy();
    102        }
    103    }