/* * (C) Copyright 2015 Nuxeo SA (http://nuxeo.com/) and others. * * 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. * * Contributors: * Delbosc Benoit */ package org.nuxeo.common.logging; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Helper to log information that can be displayed using plantuml to render sequence UML diagram. * * @since 8.1 */ public class SequenceTracer { private static final Log log = LogFactory.getLog(SequenceTracer.class); private static final String PREFIX = "@@ "; private static final String DEFAULT_COLOR = "#white"; private static final int MESSAGE_MAX_LEN = 250; // Utility class. private SequenceTracer() { } /** * Mark an event. */ public static void mark(String message) { if (!log.isDebugEnabled()) { return; } final String tn = getThreadName(); log.debug(PREFIX + tn + " -> " + tn + ": " + message); } /** * Mark the beginning of an action */ public static void start(String message) { start(message, DEFAULT_COLOR); } /** * Mark the beginning of an action */ public static void start(String message, String color) { if (!log.isDebugEnabled()) { return; } final String tn = getThreadName(); log.debug(PREFIX + tn + " -> " + tn + ": " + format(message) + "\n" + PREFIX + "activate " + tn + " " + color); } /** * Mark the beginning of an action initiated by the caller. */ public static void startFrom(final String callerThread, final String message) { startFrom(callerThread, message, DEFAULT_COLOR); } /** * Mark the beginning of an action initiated by the caller. */ public static void startFrom(final String callerThread, final String message, final String color) { if (!log.isDebugEnabled()) { return; } final String tn = getThreadName(); log.debug(PREFIX + sanitize(callerThread) + " o--> " + tn + ": Initiate\n" + PREFIX + tn + " -> " + tn + ": " + format(message) + "\n" + PREFIX + "activate " + tn + " " + color); } private static String format(String message) { String ret = sanitize(message).replace(", ", ",\\n"); ret = insertNewLine(ret); return ret; } private static String sanitize(String message) { String ret = message.replace("-", "_").replace(":", "_"); if (ret.length() > MESSAGE_MAX_LEN) { ret = ret.substring(0, MESSAGE_MAX_LEN) + "..."; } return ret; } private static String insertNewLine(String message) { return String.join("\\n", message.split("(?<=\\G.{40})")); } /** * Mark the end of the previous action. */ public static void stop(String message) { if (!log.isDebugEnabled()) { return; } final String tn = getThreadName(); log.debug(PREFIX + tn + " -> " + tn + ": " + format(message) + "\n" + PREFIX + "deactivate " + tn); } /** * Mark the last action as failure */ public static void destroy(String message) { if (!log.isDebugEnabled()) { return; } final String tn = getThreadName(); log.debug(PREFIX + tn + " -> " + tn + ": " + format(message) + "\n" + PREFIX + "destroy " + tn); } /** * Add a note on the current thread */ public static void addNote(String message) { if (!log.isDebugEnabled()) { return; } log.debug(PREFIX + "note right of " + getThreadName() + ": " + message); } /** * Link from source to current thread. */ public static void addRelation(String source, String message) { if (!log.isDebugEnabled()) { return; } log.debug(PREFIX + source + " --> " + getThreadName() + ": " + format(message)); } /** * Get the thread name sanitized for plantuml */ public static String getThreadName() { return sanitize(Thread.currentThread().getName()); } public static boolean isEnabled() { return log.isDebugEnabled(); } }