/* * Copyright © 2015 Cask Data, 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 co.cask.cdap.etl.log; import com.google.common.base.Throwables; import org.slf4j.MDC; import java.util.concurrent.Callable; /** * Controls what the current ETL stage is for logging. Log messages will be prefixed with the ETL * stage name if it is set. */ public class LogContext { private static volatile boolean enabled = false; static final String STAGE = "cdap.etl.stage"; private LogContext() { } public static void enable() { enabled = true; } /** * Run the specified command with the specified stage name. Messages logged within the command * will be prefixed with the stage name unless they are logged within a call to {@link #runWithoutLogging(Callable)}. * * @param command the command to run * @param stageName the name of the stage the command is being run in * @param <T> the type of object returned by the command * @return the result of running the command * @throws Exception if the command throws an exception */ public static <T> T run(Callable<T> command, String stageName) throws Exception { if (enabled) { MDC.put(STAGE, stageName); try { return command.call(); } finally { MDC.remove(STAGE); } } else { return command.call(); } } /** * Run the specified command with the specified stage name. Messages logged within the command * will be prefixed with the stage name unless they are logged within a call to {@link #runWithoutLogging(Callable)}. * This can be called instead of {@link #run(Callable, String)} if the command does not throw any checked * exceptions. * * @param command the command to run * @param stageName the name of the stage the command is being run in * @param <T> the type of object returned by the command * @return the result of running the command */ public static <T> T runUnchecked(Callable<T> command, String stageName) { if (enabled) { MDC.put(STAGE, stageName); try { return runUnchecked(command); } finally { MDC.remove(STAGE); } } else { return runUnchecked(command); } } /** * Run the specified command and leave out the stage name prefix for messages logged within the command. * Used to run CDAP system calls within a command passed to {@link #run(Callable, String)}. * * @param command the command to run * @param <T> the type of object returned by the command * @return the result of running the command * @throws Exception if the command throws an exception */ public static <T> T runWithoutLogging(Callable<T> command) throws Exception { if (enabled) { String stage = MDC.get(STAGE); if (stage == null) { return command.call(); } MDC.remove(STAGE); try { return command.call(); } finally { MDC.put(STAGE, stage); } } else { return command.call(); } } /** * Run the specified command and leave out the stage name prefix for messages logged within the command. * Used to run CDAP system calls within a command passed to {@link #run(Callable, String)}. * This can be called instead of {@link #runWithoutLogging(Callable)} if the command does not throw any checked * exceptions. * * @param command the command to run * @param <T> the type of object returned by the command * @return the result of running the command */ public static <T> T runWithoutLoggingUnchecked(Callable<T> command) { if (enabled) { String stage = MDC.get(STAGE); if (stage == null) { return runUnchecked(command); } MDC.remove(STAGE); try { return runUnchecked(command); } finally { MDC.put(STAGE, stage); } } else { return runUnchecked(command); } } private static <T> T runUnchecked(Callable<T> command) { try { return command.call(); } catch (Exception e) { Throwables.propagateIfPossible(e); // this shouldn't happen unless the caller is behaving badly and passes // in a command that does throw a check exception throw Throwables.propagate(e); } } }