001/* 002 * Copyright 2012 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.monitoring; 017 018import java.io.File; 019import java.util.ArrayList; 020import java.util.HashMap; 021import java.util.LinkedHashMap; 022import java.util.List; 023import java.util.Map; 024import java.util.Timer; 025import java.util.TimerTask; 026 027import javax.mail.MessagingException; 028 029import org.apache.avalon.framework.activity.Disposable; 030import org.apache.avalon.framework.activity.Initializable; 031import org.apache.avalon.framework.component.Component; 032import org.apache.avalon.framework.logger.LogEnabled; 033import org.apache.avalon.framework.logger.Logger; 034import org.apache.avalon.framework.service.ServiceException; 035import org.apache.avalon.framework.service.ServiceManager; 036import org.apache.avalon.framework.service.Serviceable; 037import org.apache.commons.io.FileUtils; 038import org.rrd4j.core.RrdDb; 039 040import org.ametys.core.util.I18nUtils; 041import org.ametys.core.util.mail.SendMailHelper; 042import org.ametys.runtime.config.Config; 043import org.ametys.runtime.i18n.I18nizableText; 044import org.ametys.runtime.plugins.admin.jvmstatus.monitoring.alerts.AlertSampleManager; 045import org.ametys.runtime.plugins.admin.jvmstatus.monitoring.alerts.AlertSampleManager.Threshold; 046import org.ametys.runtime.servlet.RuntimeConfig; 047 048/** 049 * {@link TimerTask} for creating and feeding RRDs files in order to 050 * produce graphs for monitoring: 051 * <ul> 052 * <li>JVM uptime 053 * <li>JVM memory status 054 * <li>JVM thread count 055 * <li>Servlet Engine request count 056 * <li>Servlet Engine session count 057 * </ul> 058 */ 059public class RRDsFeederTimerTask extends TimerTask implements Component, LogEnabled, Serviceable, Initializable, Disposable, MonitoringConstants 060{ 061 private static final String __CONFIG_ALERTS_ENABLED = "runtime.system.alerts.enable"; 062 private static final String __CONFIG_FROM_MAIL = "smtp.mail.from"; 063 private static final String __CONFIG_ADMIN_MAIL = "smtp.mail.sysadminto"; 064 065 private Logger _logger; 066 private MonitoringExtensionPoint _monitoringExtensionPoint; 067 private Timer _timer; 068 private String _rrdStoragePath; 069 private I18nUtils _i18nUtils; 070 071 /** Tells if there is a current alert, i.e. if we already sent an alert email 072 * This is a map {sampleManagerId -> datasourceName -> wasAlertedLastTime} */ 073 private Map<String, Map<String, Boolean>> _currentAlerts; 074 075 public void enableLogging(Logger logger) 076 { 077 _logger = logger; 078 } 079 080 public void service(ServiceManager manager) throws ServiceException 081 { 082 _monitoringExtensionPoint = (MonitoringExtensionPoint) manager.lookup(MonitoringExtensionPoint.ROLE); 083 _i18nUtils = (I18nUtils) manager.lookup(I18nUtils.ROLE); 084 } 085 086 public void initialize() throws Exception 087 { 088 _rrdStoragePath = FileUtils.getFile(RuntimeConfig.getInstance().getAmetysHome(), RRD_STORAGE_DIRECTORY).getPath(); 089 090 _logger.debug("Starting timer"); 091 // Daemon thread 092 _timer = new Timer("RRDFeeder", true); 093 // Start in 30s and refresh each minutes 094 _timer.scheduleAtFixedRate(this, 30000, FEEDING_PERIOD * 1000); 095 096 _currentAlerts = new LinkedHashMap<>(); 097 } 098 099 @Override 100 public void run() 101 { 102 if (_logger.isDebugEnabled()) 103 { 104 _logger.debug("Time to collect data"); 105 } 106 107 for (String extensionId : _monitoringExtensionPoint.getExtensionsIds()) 108 { 109 SampleManager sampleManager = _monitoringExtensionPoint.getExtension(extensionId); 110 111 if (sampleManager != null) 112 { 113 String sampleName = sampleManager.getId(); 114 File rrdFile = new File(_rrdStoragePath, sampleName + RRD_EXT); 115 116 if (_logger.isDebugEnabled()) 117 { 118 _logger.debug("Collecting sample for: " + sampleName); 119 } 120 121 try (RrdDb rrdDb = RrdDb.of(rrdFile.getPath())) 122 { 123 Map<String, Object> collectedValues = sampleManager.collect(rrdDb.createSample()); 124 if (sampleManager instanceof AlertSampleManager) 125 { 126 _checkIfAlert((AlertSampleManager) sampleManager, collectedValues); 127 } 128 } 129 catch (Exception e) 130 { 131 _logger.error("Unable to collect sample for: " + sampleName, e); 132 } 133 } 134 } 135 } 136 137 private void _checkIfAlert(AlertSampleManager sampleManager, Map<String, Object> collectedValues) 138 { 139 if (Config.getInstance() == null) 140 { 141 return; 142 } 143 144 if (Config.getInstance().getValue(__CONFIG_ALERTS_ENABLED, true, false)) 145 { 146 if (_currentAlerts.get(sampleManager.getId()) == null) 147 { 148 _currentAlerts.put(sampleManager.getId(), new HashMap<>()); 149 } 150 151 Map<String, Threshold> thresholds = sampleManager.getThresholdValues(); 152 for (String datasourceName : thresholds.keySet()) 153 { 154 if (_currentAlerts.get(sampleManager.getId()).get(datasourceName) == null) 155 { 156 _currentAlerts.get(sampleManager.getId()).put(datasourceName, false); 157 } 158 159 Threshold threshold = thresholds.get(datasourceName); 160 if (threshold.isExceeded(collectedValues.get(datasourceName)) && !_currentAlerts.get(sampleManager.getId()).get(datasourceName)) 161 { 162 // Send the mail 163 _sendAlertMail(threshold.getMailSubject(), threshold.getMailBody(), collectedValues.get(datasourceName).toString(), threshold.getValue().toString()); 164 // Memorize to not send a mail again 165 _currentAlerts.get(sampleManager.getId()).put(datasourceName, true); 166 } 167 else if (!threshold.isExceeded(collectedValues.get(datasourceName)) && _currentAlerts.get(sampleManager.getId()).get(datasourceName)) 168 { 169 // Next check, we would possibly send a mail 170 _currentAlerts.get(sampleManager.getId()).put(datasourceName, false); 171 } 172 } 173 } 174 } 175 176 private void _sendAlertMail(I18nizableText subject, I18nizableText body, String currentValue, String thresholdValue) 177 { 178 Config config = Config.getInstance(); 179 String toMail = config.getValue(__CONFIG_ADMIN_MAIL); 180 String fromMail = config.getValue(__CONFIG_FROM_MAIL); 181 try 182 { 183 String subjectStr = _i18nUtils.translate(subject, "fr"); //FIXME fr hardcoded 184 185 List<String> bodyParams = new ArrayList<>(); 186 bodyParams.add(currentValue); 187 bodyParams.add(thresholdValue); 188 I18nizableText bodyWithParams = body.isI18n() ? new I18nizableText(body.getCatalogue(), body.getKey(), bodyParams) : body; 189 String bodyStr = _i18nUtils.translate(bodyWithParams, "fr"); 190 191 SendMailHelper.sendMail(subjectStr, null, bodyStr, toMail, fromMail); 192 } 193 catch (MessagingException e) 194 { 195 if (_logger.isWarnEnabled()) 196 { 197 _logger.warn("Could not send an alert e-mail to " + toMail, e); 198 } 199 } 200 } 201 202 public void dispose() 203 { 204 _logger = null; 205 _monitoringExtensionPoint = null; 206 _rrdStoragePath = null; 207 cancel(); 208 _timer.cancel(); 209 } 210}