001/*
002 *  Copyright 2015 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.runtime.plugins.admin.jvmstatus;
017
018import java.io.File;
019import java.io.IOException;
020import java.lang.management.ManagementFactory;
021import java.lang.management.MemoryMXBean;
022import java.lang.management.RuntimeMXBean;
023import java.lang.management.ThreadMXBean;
024import java.util.ArrayList;
025import java.util.Collections;
026import java.util.Date;
027import java.util.HashMap;
028import java.util.HashSet;
029import java.util.List;
030import java.util.Map;
031import java.util.Set;
032
033import org.apache.avalon.framework.activity.Initializable;
034import org.apache.avalon.framework.component.Component;
035import org.apache.avalon.framework.logger.AbstractLogEnabled;
036import org.apache.avalon.framework.service.ServiceException;
037import org.apache.avalon.framework.service.ServiceManager;
038import org.apache.avalon.framework.service.Serviceable;
039import org.apache.commons.io.FileUtils;
040import org.rrd4j.core.Archive;
041import org.rrd4j.core.RrdDb;
042
043import org.ametys.core.ui.Callable;
044import org.ametys.core.util.I18nUtils;
045import org.ametys.runtime.parameter.ParameterHelper;
046import org.ametys.runtime.plugins.admin.jvmstatus.monitoring.MonitoringConstants;
047import org.ametys.runtime.plugins.admin.jvmstatus.monitoring.MonitoringExtensionPoint;
048import org.ametys.runtime.plugins.admin.jvmstatus.monitoring.SampleManager;
049import org.ametys.runtime.plugins.admin.jvmstatus.monitoring.alerts.AlertSampleManager;
050import org.ametys.runtime.plugins.admin.jvmstatus.monitoring.alerts.AlertSampleManager.Threshold;
051import org.ametys.runtime.servlet.RuntimeConfig;
052
053/**
054 * This helper allow to get information or runs some operations on JVM system
055 */
056public class JVMStatusHelper extends AbstractLogEnabled implements Component, Serviceable, Initializable, MonitoringConstants
057{
058    /** The monitoring extension point */
059    private MonitoringExtensionPoint _monitoringExtensionPoint;
060    
061    /** Component containing i18n utilitary methods */
062    private I18nUtils _i18nUtils;
063
064    private String _rrdStoragePath;
065    
066    @Override
067    public void service(ServiceManager manager) throws ServiceException
068    {
069        _monitoringExtensionPoint = (MonitoringExtensionPoint) manager.lookup(MonitoringExtensionPoint.ROLE);
070        _i18nUtils = (I18nUtils) manager.lookup(I18nUtils.ROLE);
071    }
072    
073    public void initialize() throws Exception
074    {
075        _rrdStoragePath = FileUtils.getFile(RuntimeConfig.getInstance().getAmetysHome(), RRD_STORAGE_DIRECTORY).getPath();
076    }
077    
078    /**
079     * Runs a garbage collector.
080     * @return an empty map
081     */
082    @Callable
083    public Map<String, Object> garbageCollect ()
084    {
085        if (getLogger().isInfoEnabled())
086        {
087            getLogger().info("Administrator is garbage collecting");
088        }
089        
090        System.gc();
091        
092        return Collections.EMPTY_MAP;
093    }
094    
095    /**
096     * Retrieves information about the general status of the system 
097     * @return a map containing the general status information
098     */
099    @Callable
100    public Map<String, Object> getGeneralStatus()
101    {
102        Map<String, Object> result = new HashMap<>();
103
104        result.put("osTime", ParameterHelper.valueToString(new Date()));
105        try
106        {
107            result.put("activeSessions", SessionCountListener.getSessionCount());
108        }
109        catch (IllegalStateException e)
110        {
111            // empty : no value in activeSession means an error
112        }
113        
114        try
115        {
116            result.put("activeRequests", RequestCountListener.getCurrentRequestCount());
117        }
118        catch (IllegalStateException e)
119        {
120            // empty : no value in activeSession means an error
121        }
122        
123        
124        ThreadMXBean tBean = ManagementFactory.getThreadMXBean();
125        MemoryMXBean mBean = ManagementFactory.getMemoryMXBean();
126        RuntimeMXBean rBean = ManagementFactory.getRuntimeMXBean();
127        
128        result.put("activeThreads", tBean.getThreadCount());
129        long[] lockedThreads = ManagementFactory.getThreadMXBean().findMonitorDeadlockedThreads();
130        
131        result.put("deadlockThreads", lockedThreads != null ? String.valueOf(lockedThreads.length) : "0");
132    
133        result.put("heap-memory-max", mBean.getHeapMemoryUsage().getMax());
134        result.put("heap-memory-used", mBean.getHeapMemoryUsage().getUsed());
135        result.put("heap-memory-commited", mBean.getHeapMemoryUsage().getCommitted());
136        
137        result.put("startTime", ParameterHelper.valueToString(new Date(rBean.getStartTime())));
138        
139        return result;
140    }
141    
142    /**
143     * Retrieves the monitoring data 
144     * @return a map containing the monitoring data
145     */
146    @Callable
147    public Map<String, Object> getMonitoringData()
148    {
149        Map<String, Object> result = new HashMap<> ();
150        
151        Map<String, Object> samples = new HashMap<> ();
152        List<String> periods = new ArrayList<> ();
153        
154        for (Period period : Period.values())
155        {
156            periods.add(period.toString());
157        }
158        
159        samples.put("periods", periods);
160        
161        List<Map<String, Object>> sampleList = new ArrayList<> ();
162        for (String extensionId : _monitoringExtensionPoint.getExtensionsIds())
163        {
164            Map<String, Object> sample = new HashMap<> ();
165            SampleManager sampleManager = _monitoringExtensionPoint.getExtension(extensionId);
166
167            sample.put("id", sampleManager.getId());
168            sample.put("label", _i18nUtils.translate(sampleManager.getLabel()));
169            sample.put("description", _i18nUtils.translate(sampleManager.getDescription()));
170            if (sampleManager instanceof AlertSampleManager)
171            {
172                Map<String, Object> thresholdValues = new HashMap<>(); 
173                
174                Map<String, Threshold> thresholds = ((AlertSampleManager) sampleManager).getThresholdValues();
175                for (String datasourceName : thresholds.keySet())
176                {
177                    thresholdValues.put(datasourceName, thresholds.get(datasourceName).getValue());
178                }
179                
180                sample.put("thresholds", thresholdValues);
181            }
182
183            File rrdFile = new File(_rrdStoragePath, sampleManager.getId() + RRD_EXT);
184            if (getLogger().isDebugEnabled())
185            {
186                getLogger().debug("Using RRD file: " + rrdFile);
187            }
188            
189            RrdDb rrdDb = null;
190            try
191            {
192                rrdDb = new RrdDb(rrdFile.getPath());
193                
194                sample.put("ds", rrdDb.getDsNames());
195                
196                Set<String> consolidationFunction = new HashSet<>();
197                for (int i = 0; i < rrdDb.getArcCount(); i++)
198                {
199                    Archive archive = rrdDb.getArchive(i);
200                    consolidationFunction.add(archive.getConsolFun().toString());
201                }
202                sample.put("consolFun", consolidationFunction);
203            }
204            catch (Exception e)
205            {
206                getLogger().error("Unable to collect sample for: " + sampleManager.getId(), e);
207            }
208            finally
209            {
210                if (rrdDb != null)
211                {
212                    try
213                    {
214                        rrdDb.close();
215                    }
216                    catch (IOException e)
217                    {
218                        getLogger().warn("Unable to close RRD file: " + rrdFile, e);
219                    }
220                }
221            }
222            
223            sampleList.add(sample);
224        }
225        
226        samples.put("sampleList", sampleList);
227        result.put("samples", samples);
228        return result;
229    }
230}