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("activeSessionsDetail", ActiveSessionListener.getActiveSessions());
116        }
117        catch (IllegalStateException e)
118        {
119            // empty : no value in activeSession means an error
120        }
121        
122        try
123        {
124            result.put("activeRequests", RequestCountListener.getCurrentRequestCount());
125        }
126        catch (IllegalStateException e)
127        {
128            // empty : no value in activeSession means an error
129        }
130        
131        
132        ThreadMXBean tBean = ManagementFactory.getThreadMXBean();
133        MemoryMXBean mBean = ManagementFactory.getMemoryMXBean();
134        RuntimeMXBean rBean = ManagementFactory.getRuntimeMXBean();
135        
136        result.put("activeThreads", tBean.getThreadCount());
137        long[] lockedThreads = ManagementFactory.getThreadMXBean().findMonitorDeadlockedThreads();
138        
139        result.put("deadlockThreads", lockedThreads != null ? String.valueOf(lockedThreads.length) : "0");
140    
141        result.put("heap-memory-max", mBean.getHeapMemoryUsage().getMax());
142        result.put("heap-memory-used", mBean.getHeapMemoryUsage().getUsed());
143        result.put("heap-memory-commited", mBean.getHeapMemoryUsage().getCommitted());
144        
145
146        result.put("startTime", DateUtils.dateToString(new Date(rBean.getStartTime())));
147        
148        return result;
149    }
150    
151    /**
152     * Retrieves the monitoring data 
153     * @return a map containing the monitoring data
154     */
155    @Callable
156    public Map<String, Object> getMonitoringData()
157    {
158        Map<String, Object> result = new HashMap<> ();
159        
160        Map<String, Object> samples = new HashMap<> ();
161        List<String> periods = new ArrayList<> ();
162        
163        for (Period period : Period.values())
164        {
165            periods.add(period.toString());
166        }
167        
168        samples.put("periods", periods);
169        
170        List<Map<String, Object>> sampleList = new ArrayList<> ();
171        for (String extensionId : _monitoringExtensionPoint.getExtensionsIds())
172        {
173            Map<String, Object> sample = new HashMap<> ();
174            SampleManager sampleManager = _monitoringExtensionPoint.getExtension(extensionId);
175
176            sample.put("id", sampleManager.getId());
177            sample.put("label", _i18nUtils.translate(sampleManager.getLabel()));
178            sample.put("description", _i18nUtils.translate(sampleManager.getDescription()));
179            if (sampleManager instanceof AlertSampleManager)
180            {
181                Map<String, Object> thresholdValues = new HashMap<>(); 
182                
183                Map<String, Threshold> thresholds = ((AlertSampleManager) sampleManager).getThresholdValues();
184                for (String datasourceName : thresholds.keySet())
185                {
186                    thresholdValues.put(datasourceName, thresholds.get(datasourceName).getValue());
187                }
188                
189                sample.put("thresholds", thresholdValues);
190            }
191
192            File rrdFile = new File(_rrdStoragePath, sampleManager.getId() + RRD_EXT);
193            if (getLogger().isDebugEnabled())
194            {
195                getLogger().debug("Using RRD file: " + rrdFile);
196            }
197            
198            try (RrdDb rrdDb = RrdDb.of(rrdFile.getPath()))
199            {
200                sample.put("ds", rrdDb.getDsNames());
201                
202                Set<String> consolidationFunction = new HashSet<>();
203                for (int i = 0; i < rrdDb.getArcCount(); i++)
204                {
205                    Archive archive = rrdDb.getArchive(i);
206                    consolidationFunction.add(archive.getConsolFun().toString());
207                }
208                sample.put("consolFun", consolidationFunction);
209            }
210            catch (Exception e)
211            {
212                getLogger().error("Unable to collect sample for: " + sampleManager.getId(), e);
213            }
214            
215            sampleList.add(sample);
216        }
217        
218        samples.put("sampleList", sampleList);
219        result.put("samples", samples);
220        return result;
221    }
222}