/* * Copyright 2014 mango.jfaster.org * * The Mango Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jfaster.mango.stat; import org.jfaster.mango.util.logging.InternalLogger; import org.jfaster.mango.util.logging.InternalLoggerFactory; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.concurrent.*; /** * @author ash */ public class StatCollector { private final static InternalLogger logger = InternalLoggerFactory.getInstance(StatCollector.class); private final ConcurrentHashMap<Method, CombinedStat> combinedStatMap = new ConcurrentHashMap<Method, CombinedStat>(); private long timestamp = currentTimeMillis(); private ScheduledExecutorService scheduler; private ExecutorService worker; public synchronized void initStatMonitor(final StatMonitor statMonitor) { if (scheduler != null) { throw new IllegalStateException("StatMonitor is initialized many times"); } scheduler = Executors.newSingleThreadScheduledExecutor(); worker = Executors.newSingleThreadExecutor(); long periodSecond = statMonitor.periodSecond(); long nowSecond = currentTimeMillis() / 1000; long delay = (nowSecond / periodSecond) * periodSecond + periodSecond - nowSecond; // 对齐时间 scheduler.scheduleAtFixedRate(new Runnable() { @Override public void run() { final StatInfo statInfo = resetAndGetStatInfo(); worker.execute(new Runnable() { @Override public void run() { try { statMonitor.handleStat(statInfo.getStatBeginTime(), statInfo.getStatEndTime(), statInfo.getStats()); } catch (Exception e) { e.printStackTrace(); logger.error("StatMonitor handle stat error", e); } } }); } }, delay, periodSecond, TimeUnit.SECONDS); } public synchronized void shutDown() { if (scheduler != null) { scheduler.shutdown(); } if (worker != null) { worker.shutdown(); } } public synchronized StatInfo getStatInfo() { long now = currentTimeMillis(); List<OperatorStat> operatorStats = new ArrayList<OperatorStat>(); for (CombinedStat combinedStat : combinedStatMap.values()) { operatorStats.add(combinedStat.toOperatorStat()); } return StatInfo.create(timestamp, now, operatorStats); } public synchronized StatInfo resetAndGetStatInfo() { long now = currentTimeMillis(); List<CombinedStat> combinedStats = new ArrayList<CombinedStat>(); for (CombinedStat combinedStat : combinedStatMap.values()) { final ExecuteStat executeStat = combinedStat.getExecuteStat(); combinedStat.setExecuteStat(ExecuteStat.create()); combinedStats.add(CombinedStat.create(combinedStat.getMetaStat(), combinedStat.getInitStat(), executeStat)); } try { TimeUnit.MILLISECONDS.sleep(10); // 等待并发状态累加完成 } catch (InterruptedException e) { } List<OperatorStat> operatorStats = new ArrayList<OperatorStat>(); for (CombinedStat combinedStat : combinedStats) { operatorStats.add(combinedStat.toOperatorStat()); } StatInfo statInfo = StatInfo.create(timestamp, now, operatorStats); timestamp = now; return statInfo; } public CombinedStat getCombinedStat(Method method) { CombinedStat stat = combinedStatMap.get(method); if (stat == null) { stat = CombinedStat.create(); CombinedStat old = combinedStatMap.putIfAbsent(method, stat); if (old != null) { // 已经存在,就用老的,这样能保证单例 stat = old; } } return stat; } private long currentTimeMillis() { return System.currentTimeMillis(); } }