/* * Copyright 2012 LinkedIn, Inc * * 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 com.linkedin.parseq.internal; import java.util.function.Function; import com.linkedin.parseq.Exceptions; import com.linkedin.parseq.Task; import com.linkedin.parseq.trace.ResultType; import com.linkedin.parseq.trace.ShallowTrace; import org.slf4j.Logger; /** * The trace logger will log to the first logger in the following sequence that * accepts debug or trace logging. * * <ol> * <li>plan logger - logs all tasks that are created by a root task of a specified class</li> * <li>root logger - logs all root tasks</li> * <li>all logger - logs all tasks</li> * </ol> * * Use the trace level to get additional logging beyond that provided by the debug level. * * @author Chris Pettitt (cpettitt@linkedin.com) */ public class TaskLogger { private static final String START_TASK_FORMAT = "[plan={}]: Starting task '{}'"; private static final String END_TASK_DEBUG_FORMAT = "[plan={}]: Ending task '{}'. Elapsed: {}ms, Result type: {}."; private static final String END_TASK_TRACE_FORMAT = "[plan={}]: Ending task '{}'. Elapsed: {}ms, Result type: {}. Value: {}."; /** * The id of a root task for the plan. Used to determine if a given task should be * logged using the plan logger. */ private final Long _rootId; /** Logs every trace it finds. */ private final Logger _allLogger; /** Logs only root traces. */ private final Logger _rootLogger; /** Logs all tasks for this this plan. */ private final Logger _planLogger; private final Long _planId; public TaskLogger(final Long planId, final Long rootId, final Logger allLogger, final Logger rootLogger, final Logger planLogger) { _allLogger = allLogger; _rootLogger = rootLogger; _planLogger = planLogger; _rootId = rootId; _planId = planId; } public void logTaskStart(final Task<?> task) { if (_planLogger.isDebugEnabled()) { _planLogger.debug(START_TASK_FORMAT, _planId, task.getName()); } else if (_rootLogger.isDebugEnabled() && _rootId.equals(task.getId())) { _rootLogger.debug(START_TASK_FORMAT, _planId, task.getName()); } else if (_allLogger.isDebugEnabled()) { _allLogger.debug(START_TASK_FORMAT, _planId, task.getName()); } } public <T> void logTaskEnd(final Task<T> task, final Function<T, String> traceValueProvider) { if (_planLogger.isTraceEnabled()) { _planLogger.trace(END_TASK_TRACE_FORMAT, new Object[] { _planId, task.getName(), elapsedMillis(task), ResultType .fromTask(task), stringValue(task, traceValueProvider) }); } else if (_planLogger.isDebugEnabled()) { _planLogger.debug(END_TASK_DEBUG_FORMAT, new Object[] { _planId, task.getName(), elapsedMillis(task), ResultType.fromTask(task) }); } else if (_rootId.equals(task.getId()) && _rootLogger.isTraceEnabled()) { _rootLogger.trace(END_TASK_TRACE_FORMAT, new Object[] { _planId, task.getName(), elapsedMillis(task), ResultType .fromTask(task), stringValue(task, traceValueProvider) }); } else if (_rootId.equals(task.getId()) && _rootLogger.isDebugEnabled()) { _rootLogger.debug(END_TASK_DEBUG_FORMAT, new Object[] { _planId, task.getName(), elapsedMillis(task), ResultType.fromTask(task) }); } else if (_allLogger.isTraceEnabled()) { _allLogger.trace(END_TASK_TRACE_FORMAT, new Object[] { _planId, task.getName(), elapsedMillis(task), ResultType .fromTask(task), stringValue(task, traceValueProvider) }); } else if (_allLogger.isDebugEnabled()) { _allLogger.debug(END_TASK_DEBUG_FORMAT, new Object[] { _planId, task.getName(), elapsedMillis(task), ResultType.fromTask(task) }); } } private <T> String stringValue(Task<T> task, Function<T, String> traceValueProvider) { if (task.isFailed()) { return Exceptions.failureToString(task.getError()); } else { if (traceValueProvider != null) { try { return traceValueProvider.apply(task.get()); } catch (Exception e) { return e.toString(); } } } return "null"; } private long elapsedMillis(final Task<?> task) { final ShallowTrace trace = task.getShallowTrace(); return (trace.getEndNanos() - trace.getStartNanos()) / 1000000; } }