/* * Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com * The software in this package is published under the terms of the CPAL v1.0 * license, a copy of which has been included with this distribution in the * LICENSE.txt file. */ package org.mule.runtime.core.context.notification; import org.mule.runtime.api.lifecycle.Disposable; import org.mule.runtime.api.lifecycle.Initialisable; import org.mule.runtime.api.lifecycle.InitialisationException; import org.mule.runtime.core.api.EventContext; import org.mule.runtime.core.api.MuleContext; import org.mule.runtime.core.api.construct.FlowConstruct; import org.mule.runtime.core.api.context.MuleContextAware; import org.mule.runtime.core.api.context.notification.EnrichedNotificationInfo; import org.mule.runtime.core.api.context.notification.FlowCallStack; import org.mule.runtime.core.api.context.notification.FlowStackElement; import org.mule.runtime.core.api.context.notification.FlowTraceManager; import org.mule.runtime.core.api.context.notification.ProcessorsTrace; import org.mule.runtime.core.api.execution.LocationExecutionContextProvider; import org.mule.runtime.core.api.processor.Processor; import org.mule.runtime.core.config.DefaultMuleConfiguration; import org.mule.runtime.core.logging.LogConfigChangeSubject; import java.beans.PropertyChangeListener; import java.util.Collections; import java.util.Map; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.spi.LoggerContext; /** * Manager for handling message processing troubleshooting data. */ public class MessageProcessingFlowTraceManager extends LocationExecutionContextProvider implements FlowTraceManager, MuleContextAware, Initialisable, Disposable { public static final String FLOW_STACK_INFO_KEY = "FlowStack"; private final FlowNotificationTextDebugger pipelineProcessorDebugger; private final MessageProcessorTextDebugger messageProcessorTextDebugger; private MuleContext muleContext; private PropertyChangeListener logConfigChangeListener = evt -> handleNotificationListeners(); public MessageProcessingFlowTraceManager() { messageProcessorTextDebugger = new MessageProcessorTextDebugger(this); pipelineProcessorDebugger = new FlowNotificationTextDebugger(this); } @Override public void setMuleContext(MuleContext context) { this.muleContext = context; } @Override public void initialise() throws InitialisationException { LoggerContext context = LogManager.getContext(false); if (context != null && context instanceof LogConfigChangeSubject) { ((LogConfigChangeSubject) context).registerLogConfigChangeListener(logConfigChangeListener); } handleNotificationListeners(); } @Override public void dispose() { LoggerContext context = LogManager.getContext(false); if (context != null && context instanceof LogConfigChangeSubject) { ((LogConfigChangeSubject) context).unregisterLogConfigChangeListener(logConfigChangeListener); } removeNotificationListeners(); } protected void handleNotificationListeners() { if (DefaultMuleConfiguration.isFlowTrace()) { muleContext.getNotificationManager().addListener(messageProcessorTextDebugger); muleContext.getNotificationManager().addListener(pipelineProcessorDebugger); } else { removeNotificationListeners(); } } protected void removeNotificationListeners() { muleContext.getNotificationManager().removeListener(messageProcessorTextDebugger); muleContext.getNotificationManager().removeListener(pipelineProcessorDebugger); } /** * Callback method for when a message processor is about to be invoked. * <p/> * Updates the internal state of the event's {@link ProcessorsTrace} and {@link FlowCallStack} accordingly. * * @see DefaultProcessorsTrace#addExecutedProcessors(String) * @see DefaultFlowCallStack#setCurrentProcessorPath(String) * * @param notification the notification that contains the event and the processor that is about to be invoked. */ public void onMessageProcessorNotificationPreInvoke(MessageProcessorNotification notification) { String resolveProcessorRepresentation = resolveProcessorRepresentation(muleContext.getConfiguration().getId(), notification.getComponent().getLocation().getLocation(), notification.getProcessor()); EventContext eventContext = notification.getEventContext(); if (eventContext != null) { ((DefaultProcessorsTrace) eventContext.getProcessorsTrace()) .addExecutedProcessors(resolveProcessorRepresentation); } if (notification.getFlowCallStack() != null) { ((DefaultFlowCallStack) notification.getFlowCallStack()) .setCurrentProcessorPath(resolveProcessorRepresentation); } } /** * Callback method for when a flow or sub-flow called from a {@code flow-ref} component has been completed. * * @param notification the notification that contains the event and the processor that is about to be invoked. */ public void onPipelineNotificationComplete(PipelineMessageNotification notification) { onFlowComplete(notification.getInfo()); } /** * Callback method for when a flow or sub-flow is about to be called from a {@code flow-ref}. * * @param notification the notification that contains the event and the processor that is about to be invoked. */ public void onPipelineNotificationStart(PipelineMessageNotification notification) { onFlowStart(notification.getInfo(), notification.getFlowConstruct().getName()); } @Override public void onFlowStart(EnrichedNotificationInfo notificationInfo, String flowName) { if (notificationInfo.getFlowCallStack() instanceof DefaultFlowCallStack) { ((DefaultFlowCallStack) notificationInfo.getFlowCallStack()).push(new FlowStackElement(flowName, null)); } } @Override public void onFlowComplete(EnrichedNotificationInfo notificationInfo) { if (notificationInfo.getFlowCallStack() instanceof DefaultFlowCallStack) { ((DefaultFlowCallStack) notificationInfo.getFlowCallStack()).pop(); } } @Override public Map<String, Object> getContextInfo(EnrichedNotificationInfo notificationInfo, Processor lastProcessed, FlowConstruct flowConstruct) { if (DefaultMuleConfiguration.isFlowTrace()) { return Collections.<String, Object>singletonMap(FLOW_STACK_INFO_KEY, notificationInfo.getFlowCallStack().toString()); } else { return Collections.<String, Object>emptyMap(); } } }