/* * Copyright 2016 the original author or authors. * * Licensed 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.springframework.statemachine.boot.support; import java.util.HashMap; import java.util.Map; import org.springframework.boot.actuate.metrics.CounterService; import org.springframework.boot.actuate.metrics.GaugeService; import org.springframework.boot.actuate.trace.TraceRepository; import org.springframework.statemachine.StateMachine; import org.springframework.statemachine.action.Action; import org.springframework.statemachine.monitor.AbstractStateMachineMonitor; import org.springframework.statemachine.monitor.StateMachineMonitor; import org.springframework.statemachine.state.State; import org.springframework.statemachine.transition.Transition; import org.springframework.util.ObjectUtils; /** * Implementation of a {@link StateMachineMonitor} which converts monitoring * events and bridges those into supported format handled by Spring Boot's * tracing and metrics frameworks. * * @author Janne Valkealahti * * @param <S> the type of state * @param <E> the type of event */ public class BootStateMachineMonitor<S, E> extends AbstractStateMachineMonitor<S, E> { private final String METRIC_TRANSITION_BASE = "ssm.transition"; private final String METRIC_ACTION_BASE = "ssm.action"; private final CounterService counterService; private final GaugeService gaugeService; private final TraceRepository traceRepository; /** * Instantiates a new boot state machine monitor. * * @param counterService the counter service * @param gaugeService the gauge service * @param traceRepository the trace repository */ public BootStateMachineMonitor(CounterService counterService, GaugeService gaugeService, TraceRepository traceRepository) { this.counterService = counterService; this.gaugeService = gaugeService; this.traceRepository = traceRepository; } @Override public void transition(StateMachine<S, E> stateMachine, Transition<S, E> transition, long duration) { String transitionName = transitionToName(transition); this.counterService.increment(METRIC_TRANSITION_BASE + "." + transitionName + ".transit"); this.gaugeService.submit(METRIC_TRANSITION_BASE + "." + transitionName + ".duration", duration); Map<String, Object> traceInfo = new HashMap<>(); traceInfo.put("transition", transitionToName(transition)); traceInfo.put("duration", duration); traceInfo.put("machine", stateMachine.getId()); traceRepository.add(traceInfo); } @Override public void action(StateMachine<S, E> stateMachine, Action<S, E> action, long duration) { String actionName = actionToName(action); this.counterService.increment(METRIC_ACTION_BASE + "." + actionName + ".execute"); this.gaugeService.submit(METRIC_ACTION_BASE + "." + actionName + ".duration", duration); Map<String, Object> traceInfo = new HashMap<>(); traceInfo.put("action", actionName); traceInfo.put("duration", duration); traceInfo.put("machine", stateMachine.getId()); traceRepository.add(traceInfo); } private static <S, E> String transitionToName(Transition<S, E> transition) { String sourceId = nullStateId(transition.getSource()); String targetId = nullStateId(transition.getTarget()); StringBuilder buf = new StringBuilder(); buf.append(transition.getKind()); if (sourceId != null) { buf.append("_"); buf.append(sourceId); } if (targetId != null) { buf.append("_"); buf.append(targetId); } return buf.toString(); } private static <S, E> String actionToName(Action<S, E> action) { return ObjectUtils.getDisplayString(action); } private static <S, E> String nullStateId(State<S, E> state) { if (state == null) { return null; } S id = state.getId(); return id != null ? id.toString() : null; } }