/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.apache.synapse.aspects.flow.statistics.collectors;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.synapse.MessageContext;
import org.apache.synapse.aspects.flow.statistics.log.StatisticsReportingEvent;
import org.apache.synapse.aspects.flow.statistics.log.StatisticsReportingEventHolder;
import org.apache.synapse.aspects.flow.statistics.util.MediationFlowController;
import org.apache.synapse.aspects.flow.statistics.util.StatisticDataCollectionHelper;
import org.apache.synapse.aspects.flow.statistics.util.StatisticsConstants;
import org.apache.synapse.config.SynapseConfigUtils;
import org.apache.synapse.config.SynapsePropertiesLoader;
/**
* RuntimeStatisticCollector receives statistic events and responsible for handling each of these events.
*/
public abstract class RuntimeStatisticCollector {
private static final Log log = LogFactory.getLog(RuntimeStatisticCollector.class);
/**
* Is statistics collection enabled in synapse.properties file.
*/
private static boolean isStatisticsEnabled;
/**
* Is payload collection enabled in synapse.properties file.
*/
private static boolean isCollectingPayloads;
/**
* Is message context property collection enabled in synapse.properties file.
*/
private static boolean isCollectingProperties;
/**
* Is collecting statistics of all artifacts
*/
private static boolean isCollectingAllStatistics;
public static long eventExpireTime;
/**
* Initialize statistics collection when ESB starts.
*/
public static void init() {
isStatisticsEnabled = Boolean.parseBoolean(
SynapsePropertiesLoader.getPropertyValue(StatisticsConstants.STATISTICS_ENABLE, String.valueOf(false)));
if (isStatisticsEnabled) {
if (log.isDebugEnabled()) {
log.debug("Mediation statistics collection is enabled.");
}
Long eventConsumerTime = Long.parseLong(SynapsePropertiesLoader.getPropertyValue(
StatisticsConstants.FLOW_STATISTICS_EVENT_CONSUME_TIME,
StatisticsConstants.FLOW_STATISTICS_DEFAULT_EVENT_CONSUME_INTERVAL));
isCollectingPayloads = Boolean.parseBoolean(SynapsePropertiesLoader.getPropertyValue(
StatisticsConstants.COLLECT_MESSAGE_PAYLOADS, String.valueOf(false)));
if (!isCollectingPayloads && log.isDebugEnabled()) {
log.debug("Payload collecting is not enabled in \'synapse.properties\' file.");
}
isCollectingProperties = Boolean.parseBoolean(SynapsePropertiesLoader.getPropertyValue(
StatisticsConstants.COLLECT_MESSAGE_PROPERTIES, String.valueOf(false)));
if (!isCollectingProperties && log.isDebugEnabled()) {
log.debug("Property collecting is not enabled in \'synapse.properties\' file.");
}
isCollectingAllStatistics = Boolean.parseBoolean(SynapsePropertiesLoader.getPropertyValue(
StatisticsConstants.COLLECT_ALL_STATISTICS, String.valueOf(false)));
eventExpireTime =
SynapseConfigUtils.getGlobalTimeoutInterval() + SynapseConfigUtils.getTimeoutHandlerInterval() +
eventConsumerTime;
log.info("Statistics Entry Expiration time set to " + eventExpireTime + " milliseconds");
new MediationFlowController();
} else {
if (log.isDebugEnabled()) {
log.debug("Statistics is not enabled in \'synapse.properties\' file.");
}
}
}
/**
* Set message Id of the message context as statistic trace Id at the beginning of the statistic flow.
*
* @param msgCtx synapse message context.
*/
protected static void setStatisticsTraceId(MessageContext msgCtx) {
if (msgCtx.getProperty(StatisticsConstants.FLOW_STATISTICS_ID) == null && msgCtx.getMessageID() != null) {
msgCtx.setProperty(StatisticsConstants.FLOW_STATISTICS_ID, msgCtx.getMessageID().replace(':', '_'));
} else if (msgCtx.getMessageID() == null) {
log.error("Message ID is null");
}
}
/**
* Returns true if statistics is collected in this message flow path.
*
* @param messageContext synapse message context.
* @return true if statistics is collected in the message flow.
*/
public static boolean shouldReportStatistic(MessageContext messageContext) {
if (!isStatisticsEnabled) {
return false;
}
Boolean isStatCollected =
(Boolean) messageContext.getProperty(StatisticsConstants.FLOW_STATISTICS_IS_COLLECTED);//todo try use one object
Object statID = messageContext.getProperty(StatisticsConstants.FLOW_STATISTICS_ID);
return (statID != null && isStatCollected != null && isStatCollected);
}
/**
* Returns whether statistics collection is enabled globally for the esb as specified in the
* synapse.properties file.
*
* @return true if statistics collection is enabled.
*/
public static boolean isStatisticsEnabled() {
return isStatisticsEnabled;
}
/**
* Return whether collecting payloads is enabled.
*
* @return true if need to collect payloads.
*/
public static boolean isCollectingPayloads() {
return isStatisticsEnabled && isCollectingPayloads;
}
/**
* Return whether collecting message-properties is enabled.
*
* @return true if need to collect message-properties.
*/
public static boolean isCollectingProperties() {
return isStatisticsEnabled && isCollectingProperties;
}
/**
* Return whether collecting statistics for all artifacts is enabled (this also needs isStatisticsEnabled)
*
* @return true if need to collect statistics for all artifacts
*/
public static boolean isCollectingAllStatistics() {
return isStatisticsEnabled && isCollectingAllStatistics;
}
/**
* Allow external to alter state of collecting statistics for all artifacts, during runtime
*/
public static void setCollectingAllStatistics(boolean state) {
isCollectingAllStatistics = state;
log.info("Collecting statistics for all artifacts state changed to: " + state);
}
/**
* Helper method to add event and increment stat count so that it denotes, open event is added.
*
* @param messageContext
* @param event
*/
protected static void addEventAndIncrementCount(MessageContext messageContext, StatisticsReportingEvent event) {
StatisticsReportingEventHolder eventHolder = (StatisticsReportingEventHolder) messageContext.getProperty(StatisticsConstants.STAT_COLLECTOR_PROPERTY);
if (eventHolder == null) {
eventHolder = new StatisticsReportingEventHolder();
messageContext.setProperty(StatisticsConstants.STAT_COLLECTOR_PROPERTY, eventHolder);
}
if (eventHolder.isEvenCollectionFinished()) {
handleError(eventHolder, event);
return;
}
eventHolder.addEvent(event);
eventHolder.countHolder.incrementStatCount();
}
/**
* Helper method to add event and decrement stat count, which denotes, closing event happened.
*
* @param messageContext
* @param event
*/
protected static void addEventAndDecrementCount(MessageContext messageContext, StatisticsReportingEvent event) {
StatisticsReportingEventHolder eventHolder = (StatisticsReportingEventHolder) messageContext.getProperty(StatisticsConstants.STAT_COLLECTOR_PROPERTY);
if (eventHolder == null) {
eventHolder = new StatisticsReportingEventHolder();
messageContext.setProperty(StatisticsConstants.STAT_COLLECTOR_PROPERTY, eventHolder);
}
if (eventHolder.isEvenCollectionFinished()) {
handleError(eventHolder, event);
return;
}
eventHolder.addEvent(event);
if (eventHolder.countHolder.decrementAndGetStatCount() <= 0 && eventHolder.countHolder.getCallBackCount() <= 0) {
eventHolder.setEvenCollectionFinished(true);
messageContext.getEnvironment().getMessageDataStore().enqueue(eventHolder);
}
}
/**
* Helper method to add event and increment call back count, which notifies that a callback has been registered
*
* @param messageContext
* @param event
*/
protected static void addEventAndIncrementCallbackCount(MessageContext messageContext,
StatisticsReportingEvent event) {
StatisticsReportingEventHolder eventHolder = (StatisticsReportingEventHolder) messageContext.getProperty(StatisticsConstants.STAT_COLLECTOR_PROPERTY);
if (eventHolder == null) {
eventHolder = new StatisticsReportingEventHolder();
messageContext.setProperty(StatisticsConstants.STAT_COLLECTOR_PROPERTY, eventHolder);
}
if (eventHolder.isEvenCollectionFinished()) {
handleError(eventHolder, event);
return;
}
eventHolder.addEvent(event);
eventHolder.countHolder.incrementCallBackCount();
}
/**
* Helper method to add event and decrement call back count, which denotes, call back has been received.
*
* @param messageContext
* @param event
*/
protected static void addEventAndDecrementCallbackCount(MessageContext messageContext,
StatisticsReportingEvent event) {
StatisticsReportingEventHolder eventHolder = (StatisticsReportingEventHolder) messageContext.getProperty(StatisticsConstants.STAT_COLLECTOR_PROPERTY);
if (eventHolder == null) {
eventHolder = new StatisticsReportingEventHolder();
messageContext.setProperty(StatisticsConstants.STAT_COLLECTOR_PROPERTY, eventHolder);
}
if (eventHolder.isEvenCollectionFinished()) {
handleError(eventHolder, event);
return;
}
eventHolder.addEvent(event);
if (eventHolder.countHolder.decrementAndGetCallbackCount() <= 0 && eventHolder.countHolder.getStatCount() <= 0) {
eventHolder.setEvenCollectionFinished(true);
messageContext.getEnvironment().getMessageDataStore().enqueue(eventHolder);
}
}
/**
* Helper method to just add event without changing counts.
*
* @param messageContext
* @param event
*/
protected static void addEvent(MessageContext messageContext, StatisticsReportingEvent event) {
StatisticsReportingEventHolder eventHolder = (StatisticsReportingEventHolder) messageContext.getProperty(StatisticsConstants.STAT_COLLECTOR_PROPERTY);
if (eventHolder == null) {
eventHolder = new StatisticsReportingEventHolder();
messageContext.setProperty(StatisticsConstants.STAT_COLLECTOR_PROPERTY, eventHolder);
}
if (eventHolder.isEvenCollectionFinished()) {
handleError(eventHolder, event);
return;
}
eventHolder.addEvent(event);
}
/**
* Helper method to add event and close the message flow static collection.
*
* @param messageContext
* @param event
*/
protected static void addEventAndCloseFlow(MessageContext messageContext, StatisticsReportingEvent event) {
StatisticsReportingEventHolder eventHolder = (StatisticsReportingEventHolder) messageContext.getProperty(StatisticsConstants.STAT_COLLECTOR_PROPERTY);
if (eventHolder == null) {
eventHolder = new StatisticsReportingEventHolder();
messageContext.setProperty(StatisticsConstants.STAT_COLLECTOR_PROPERTY, eventHolder);
}
synchronized (eventHolder) {
if (eventHolder.isEvenCollectionFinished()) {
handleError(eventHolder, event);
return;
}
eventHolder.addEvent(event);
eventHolder.setEvenCollectionFinished(true);
eventHolder.setMessageFlowError(true);
messageContext.getEnvironment().getMessageDataStore().enqueue(eventHolder);
}
}
/**
* Helper method to handle errors.
*
* @param eventHolder
* @param event
*/
private static void handleError(StatisticsReportingEventHolder eventHolder, StatisticsReportingEvent event) {
if (eventHolder.isMessageFlowError()) {
if (log.isDebugEnabled()) {
log.debug("Message flow error happened, dropping event - " + event.getDataUnit().getStatisticId());
}
return;
}
log.warn("Events occur after event collection is finished, event - " + event.getDataUnit().getStatisticId());
}
}