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.lang.management.ManagementFactory;
020import java.lang.management.MemoryMXBean;
021import java.lang.management.RuntimeMXBean;
022import java.lang.management.ThreadMXBean;
023import java.util.ArrayList;
024import java.util.Collections;
025import java.util.Date;
026import java.util.HashMap;
027import java.util.HashSet;
028import java.util.List;
029import java.util.Map;
030import java.util.Set;
031
032import org.apache.avalon.framework.activity.Initializable;
033import org.apache.avalon.framework.component.Component;
034import org.apache.avalon.framework.logger.AbstractLogEnabled;
035import org.apache.avalon.framework.service.ServiceException;
036import org.apache.avalon.framework.service.ServiceManager;
037import org.apache.avalon.framework.service.Serviceable;
038import org.apache.commons.io.FileUtils;
039import org.rrd4j.core.Archive;
040import org.rrd4j.core.RrdDb;
041
042import org.ametys.core.ui.Callable;
043import org.ametys.core.util.DateUtils;
044import org.ametys.core.util.I18nUtils;
045import org.ametys.runtime.plugins.admin.jvmstatus.monitoring.MonitoringConstants;
046import org.ametys.runtime.plugins.admin.jvmstatus.monitoring.MonitoringExtensionPoint;
047import org.ametys.runtime.plugins.admin.jvmstatus.monitoring.SampleManager;
048import org.ametys.runtime.plugins.admin.jvmstatus.monitoring.alerts.AlertSampleManager;
049import org.ametys.runtime.plugins.admin.jvmstatus.monitoring.alerts.AlertSampleManager.Threshold;
050import org.ametys.runtime.servlet.RuntimeConfig;
051
052/**
053 * This helper allow to get information or runs some operations on JVM system
054 */
055public class JVMStatusHelper extends AbstractLogEnabled implements Component, Serviceable, Initializable, MonitoringConstants
056{
057    /** The monitoring extension point */
058    private MonitoringExtensionPoint _monitoringExtensionPoint;
059    
060    /** Component containing i18n utilitary methods */
061    private I18nUtils _i18nUtils;
062
063    private String _rrdStoragePath;
064    
065    @Override
066    public void service(ServiceManager manager) throws ServiceException
067    {
068        _monitoringExtensionPoint = (MonitoringExtensionPoint) manager.lookup(MonitoringExtensionPoint.ROLE);
069        _i18nUtils = (I18nUtils) manager.lookup(I18nUtils.ROLE);
070    }
071    
072    public void initialize() throws Exception
073    {
074        _rrdStoragePath = FileUtils.getFile(RuntimeConfig.getInstance().getAmetysHome(), RRD_STORAGE_DIRECTORY).getPath();
075    }
076    
077    /**
078     * Runs a garbage collector.
079     * @return an empty map
080     */
081    @Callable
082    public Map<String, Object> garbageCollect ()
083    {
084        if (getLogger().isInfoEnabled())
085        {
086            getLogger().info("Administrator is garbage collecting");
087        }
088        
089        System.gc();
090        
091        return Collections.EMPTY_MAP;
092    }
093    
094    /**
095     * Retrieves information about the general status of the system 
096     * @return a map containing the general status information
097     */
098    @Callable
099    public Map<String, Object> getGeneralStatus()
100    {
101        Map<String, Object> result = new HashMap<>();
102        
103        result.put("osTime", DateUtils.dateToString(new Date()));
104        try
105        {
106            result.put("activeSessions", SessionCountListener.getSessionCount());
107        }
108        catch (IllegalStateException e)
109        {
110            // empty : no value in activeSession means an error
111        }
112        
113        try
114        {
115            result.put("activeRequests", RequestCountListener.getCurrentRequestCount());
116        }
117        catch (IllegalStateException e)
118        {
119            // empty : no value in activeSession means an error
120        }
121        
122        
123        ThreadMXBean tBean = ManagementFactory.getThreadMXBean();
124        MemoryMXBean mBean = ManagementFactory.getMemoryMXBean();
125        RuntimeMXBean rBean = ManagementFactory.getRuntimeMXBean();
126        
127        result.put("activeThreads", tBean.getThreadCount());
128        long[] lockedThreads = ManagementFactory.getThreadMXBean().findMonitorDeadlockedThreads();
129        
130        result.put("deadlockThreads", lockedThreads != null ? String.valueOf(lockedThreads.length) : "0");
131    
132        result.put("heap-memory-max", mBean.getHeapMemoryUsage().getMax());
133        result.put("heap-memory-used", mBean.getHeapMemoryUsage().getUsed());
134        result.put("heap-memory-commited", mBean.getHeapMemoryUsage().getCommitted());
135        
136
137        result.put("startTime", DateUtils.dateToString(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            try (RrdDb rrdDb = RrdDb.of(rrdFile.getPath()))
190            {
191                sample.put("ds", rrdDb.getDsNames());
192                
193                Set<String> consolidationFunction = new HashSet<>();
194                for (int i = 0; i < rrdDb.getArcCount(); i++)
195                {
196                    Archive archive = rrdDb.getArchive(i);
197                    consolidationFunction.add(archive.getConsolFun().toString());
198                }
199                sample.put("consolFun", consolidationFunction);
200            }
201            catch (Exception e)
202            {
203                getLogger().error("Unable to collect sample for: " + sampleManager.getId(), e);
204            }
205            
206            sampleList.add(sample);
207        }
208        
209        samples.put("sampleList", sampleList);
210        result.put("samples", samples);
211        return result;
212    }
213}