001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *      http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019package org.apache.oozie.service;
020
021import org.apache.oozie.util.Instrumentation;
022import org.apache.oozie.util.XLog;
023import org.apache.oozie.ErrorCode;
024
025import java.util.Map;
026
027
028/**
029 * This service provides an {@link Instrumentation} instance configured to support samplers. <p> This service depends
030 * on the {@link SchedulerService}. <p> The {@link #CONF_LOGGING_INTERVAL} configuration property indicates how often
031 * snapshots of the instrumentation should be logged.
032 */
033public class InstrumentationService implements Service {
034    private static final String JVM_INSTRUMENTATION_GROUP = "jvm";
035
036    public static final String CONF_PREFIX = Service.CONF_PREFIX + "InstrumentationService.";
037
038    public static final String CONF_LOGGING_INTERVAL = CONF_PREFIX + "logging.interval";
039
040    private final XLog log = XLog.getLog(XLog.INSTRUMENTATION_LOG_NAME);
041
042    protected static Instrumentation instrumentation = null;
043
044    private static boolean isEnabled = false;
045
046    /**
047     * Initialize the instrumentation service.
048     *
049     * @param services services instance.
050     */
051    @Override
052    public void init(Services services) throws ServiceException {
053        final Instrumentation instr = new Instrumentation();
054        int interval = ConfigurationService.getInt(services.getConf(), CONF_LOGGING_INTERVAL);
055        initLogging(services, instr, interval);
056        instr.addVariable(JVM_INSTRUMENTATION_GROUP, "free.memory", new Instrumentation.Variable<Long>() {
057            @Override
058            public Long getValue() {
059                return Runtime.getRuntime().freeMemory();
060            }
061        });
062        instr.addVariable(JVM_INSTRUMENTATION_GROUP, "max.memory", new Instrumentation.Variable<Long>() {
063            @Override
064            public Long getValue() {
065                return Runtime.getRuntime().maxMemory();
066            }
067        });
068        instr.addVariable(JVM_INSTRUMENTATION_GROUP, "total.memory", new Instrumentation.Variable<Long>() {
069            @Override
070            public Long getValue() {
071                return Runtime.getRuntime().totalMemory();
072            }
073        });
074        instrumentation = instr;
075        isEnabled = true;
076    }
077
078    void initLogging(Services services, final Instrumentation instr, int interval) throws ServiceException {
079        log.info("*********** Startup ***********");
080        log.info("Java System Properties: {E}{0}", mapToString(instr.getJavaSystemProperties()));
081        log.info("OS Env: {E}{0}", mapToString(instr.getOSEnv()));
082        SchedulerService schedulerService = services.get(SchedulerService.class);
083        if (schedulerService != null) {
084            instr.setScheduler(schedulerService.getScheduler());
085            if (interval > 0) {
086                Runnable instrumentationLogger = new Runnable() {
087                    @Override
088                    public void run() {
089                        try {
090                            log.info("\n" + instr.toString());
091                        }
092                        catch (Throwable ex) {
093                            log.warn("Instrumentation logging error", ex);
094                        }
095                    }
096                };
097                schedulerService.schedule(instrumentationLogger, interval, interval, SchedulerService.Unit.SEC);
098            }
099        }
100        else {
101            throw new ServiceException(ErrorCode.E0100, getClass().getName(), "SchedulerService unavailable");
102        }
103    }
104
105    private String mapToString(Map<String, String> map) {
106        String E = System.getProperty("line.separator");
107        StringBuilder sb = new StringBuilder();
108
109        for (Map.Entry<String, String> entry : map.entrySet()) {
110            sb.append("    ").append(entry.getKey()).append(" = ").append(entry.getValue()).append(E);
111        }
112
113        return sb.toString();
114    }
115
116    /**
117     * Destroy the instrumentation service.
118     */
119    @Override
120    public void destroy() {
121        isEnabled = false;
122        instrumentation = null;
123    }
124
125    /**
126     * Return the public interface for instrumentation service.
127     *
128     * @return {@link InstrumentationService}.
129     */
130    @Override
131    public Class<? extends Service> getInterface() {
132        return InstrumentationService.class;
133    }
134
135    /**
136     * Return the instrumentation instance used by the service.
137     *
138     * @return the instrumentation instance.
139     */
140    public Instrumentation get() {
141        return instrumentation;
142    }
143
144    /**
145     * Returns if the InstrumentationService is enabled or not.
146     *
147     * @return true if the InstrumentationService is enabled; false if not
148     */
149    public static boolean isEnabled() {
150        return isEnabled;
151    }
152}