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