All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.microsoft.applicationinsights.internal.perfcounter.PerformanceCounterContainer Maven / Gradle / Ivy

/*
 * ApplicationInsights-Java
 * Copyright (c) Microsoft Corporation
 * All rights reserved.
 *
 * MIT License
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this
 * software and associated documentation files (the ""Software""), to deal in the Software
 * without restriction, including without limitation the rights to use, copy, modify, merge,
 * publish, distribute, sublicense, and/or sell copies of the Software, and to permit
 * persons to whom the Software is furnished to do so, subject to the following conditions:
 * The above copyright notice and this permission notice shall be included in all copies or
 * substantial portions of the Software.
 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
 * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

package com.microsoft.applicationinsights.internal.perfcounter;

import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import com.google.common.base.Preconditions;
import com.google.common.base.Strings;

import com.microsoft.applicationinsights.TelemetryClient;
import com.microsoft.applicationinsights.extensibility.PerformanceCountersCollectionPlugin;
import com.microsoft.applicationinsights.internal.logger.InternalLogger;
import com.microsoft.applicationinsights.internal.shutdown.SDKShutdownActivity;
import com.microsoft.applicationinsights.internal.shutdown.Stoppable;
import com.microsoft.applicationinsights.internal.util.ThreadPoolUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;

/**
 * The class serves as the container of all {@link com.microsoft.applicationinsights.internal.perfcounter.PerformanceCounter}
 * 

* If there is a need for a performance counter, the user of this class should create an implementation of that interface * and then register it in this container. *

* Note that the container will only start working after the first registration of a Performance Counter. * That means that setting the timeouts is only relevant if done before the first registration of a Performance Counter. *

* The container will go through all the registered Performance Counters and will trigger their 'report' method. * By default the container will start reporting after 5 minutes and will continue doing so every 1 minute. *

* The user of this class can add (register), remove (unregister) a performance counter while the container is working. *

* The container will be stopped automatically when the application exists. *

* Created by gupele on 3/3/2015. */ public enum PerformanceCounterContainer implements Stoppable { INSTANCE; // By default the container will wait 2 minutes before the collection of performance data. private final static long START_COLLECTING_DELAY_IN_MILLIS = 60000; private final static long START_DEFAULT_MIN_DELAY_IN_MILLIS = 20000; // By default the container will collect performance data every 1 minute. public final static long DEFAULT_COLLECTION_FREQUENCY_IN_SEC = 60; private final static long MIN_COLLECTION_FREQUENCY_IN_SEC = 1; private final ConcurrentMap performanceCounters = new ConcurrentHashMap(); private volatile boolean initialized = false; private PerformanceCountersCollectionPlugin plugin; private long startCollectingDelayInMillis = START_COLLECTING_DELAY_IN_MILLIS; private long collectionFrequencyInMS = DEFAULT_COLLECTION_FREQUENCY_IN_SEC * 1000; private TelemetryClient telemetryClient; private ScheduledThreadPoolExecutor threads; /** * /** * Registers a {@link com.microsoft.applicationinsights.internal.perfcounter.PerformanceCounter} that can collect data. * * @param performanceCounter The Performance Counter. * @return True on success. */ public boolean register(PerformanceCounter performanceCounter) { Preconditions.checkNotNull(performanceCounter, "performanceCounter should be non null, non empty value"); Preconditions.checkArgument(!Strings.isNullOrEmpty(performanceCounter.getId()), "performanceCounter's id should be non null, non empty value"); initialize(); InternalLogger.INSTANCE.trace("Registering PC '%s'", performanceCounter.getId()); PerformanceCounter prev = performanceCounters.putIfAbsent(performanceCounter.getId(), performanceCounter); if (prev != null) { InternalLogger.INSTANCE.trace("Failed to store performance counter '%s', since there is already one", performanceCounter.getId()); return false; } return true; } /** * Un-registers a performance counter. * * @param performanceCounter The Performance Counter. */ public void unregister(PerformanceCounter performanceCounter) { unregister(performanceCounter.getId()); } /** * Un-registers a performance counter by its id. * * @param id The Performance Counter's id. */ public void unregister(String id) { Preconditions.checkArgument(!Strings.isNullOrEmpty(id), "id should be non null, non empty value"); InternalLogger.INSTANCE.trace("Un-registering PC '%s'", id); performanceCounters.remove(id); } /** * Gets the timeout in milliseconds that the container will wait before the first collection of Performance Counters. * * @return The first timeout in milliseconds. */ public long getStartCollectingDelayInMillis() { return startCollectingDelayInMillis; } /** * Gets the timeout in milliseconds that the container will wait between collections of Performance Counters. * * @return The timeout between collections. */ public long getCollectionFrequencyInSec() { return collectionFrequencyInMS / 1000; } /** * Stopping the collection of performance data. * * @param timeout The timeout to wait for the stop to happen. * @param timeUnit The time unit to use when waiting for the stop to happen. */ public synchronized void stop(long timeout, TimeUnit timeUnit) { if (!initialized) { return; } ThreadPoolUtils.stop(threads, timeout, timeUnit); initialized = false; } /** * Sets the timeout to wait between collection of Performance Counters. *

* The number must be a positive number *

* Note that the method will be effective if called before the first call to the 'register' method. * * @param collectionFrequencyInSec The timeout to wait between collection of Performance Counters. */ public void setCollectionFrequencyInSec(long collectionFrequencyInSec) { if (collectionFrequencyInSec <= MIN_COLLECTION_FREQUENCY_IN_SEC) { String errorMessage = String.format("Collecting Interval: illegal value '%d'. The minimum value, '%d', " + "is used instead.", collectionFrequencyInSec, MIN_COLLECTION_FREQUENCY_IN_SEC); InternalLogger.INSTANCE.error(errorMessage); collectionFrequencyInSec = MIN_COLLECTION_FREQUENCY_IN_SEC; } this.collectionFrequencyInMS = collectionFrequencyInSec * 1000; } /** * Sets the timeout to wait before the first reporting. *

* The number must be a positive number *

* Note that the method will be effective if called before the first call to the 'register' method. * * @param startCollectingDelayInMillis Timeout to wait before the first collection of performance counters in milliseconds. */ void setStartCollectingDelayInMillis(long startCollectingDelayInMillis) { if (startCollectingDelayInMillis < START_DEFAULT_MIN_DELAY_IN_MILLIS) { InternalLogger.INSTANCE.error("Start Collecting Delay: illegal value '%d'. The minimum value, '%'d, is used instead.", startCollectingDelayInMillis, START_DEFAULT_MIN_DELAY_IN_MILLIS); startCollectingDelayInMillis = START_DEFAULT_MIN_DELAY_IN_MILLIS; } this.startCollectingDelayInMillis = startCollectingDelayInMillis; } void clear() { performanceCounters.clear(); } /** * A private method that is called only when the container needs to start * collecting performance counters data. The method will schedule a callback * to be called, it will initialize a {@link com.microsoft.applicationinsights.TelemetryClient} that the Performance Counters * will use to report their data, and it will also register itself a the {@link com.microsoft.applicationinsights.internal.shutdown.SDKShutdownActivity} */ private void initialize() { if (!initialized) { synchronized (INSTANCE) { if (!initialized) { createThreadToCollect(); scheduleWork(); initialized = true; } } } } private void scheduleWork() { threads.scheduleAtFixedRate( new Runnable() { @Override public void run() { if (telemetryClient == null) { telemetryClient = new TelemetryClient(); } if (plugin != null) { try { plugin.preCollection(); } catch (ThreadDeath td) { throw td; } catch (Throwable t) { try { InternalLogger.INSTANCE.error("Error in thread scheduled for PerformanceCounterContainer" + " Exception : %s ", ExceptionUtils.getStackTrace(t)); } catch (ThreadDeath td) { throw td; } catch (Throwable t2) { // chomp } } } for (PerformanceCounter performanceCounter : performanceCounters.values()) { try { performanceCounter.report(telemetryClient); } catch (ThreadDeath td) { throw td; } catch (Throwable t) { try { InternalLogger.INSTANCE.error("Exception while reporting performance counter '%s': " + " Exception : '%s'", performanceCounter.getId(), ExceptionUtils.getStackTrace(t)); } catch (ThreadDeath td) { throw td; } catch (Throwable t2) { // chomp } } } if (plugin != null) { try { plugin.postCollection(); } catch (ThreadDeath td) { throw td; } catch (Throwable t) { try { InternalLogger.INSTANCE.error("Error while executing post collection, Exception : %s ", ExceptionUtils.getStackTrace(t)); } catch (ThreadDeath td) { throw td; } catch (Throwable t2) { // chomp } } } } }, startCollectingDelayInMillis, collectionFrequencyInMS, TimeUnit.MILLISECONDS); // Register the instance so the container is stopped when the application exits. SDKShutdownActivity.INSTANCE.register(INSTANCE); } private void createThreadToCollect() { threads = new ScheduledThreadPoolExecutor(1); threads.setThreadFactory(ThreadPoolUtils.createDaemonThreadFactory(PerformanceCounterContainer.class)); } public void setPlugin(PerformanceCountersCollectionPlugin plugin) { this.plugin = plugin; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy