All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.snowflake.client.log.JDK14Logger Maven / Gradle / Ivy

/*
 * Copyright (c) 2012-2019 Snowflake Computing Inc. All rights reserved.
 */
package net.snowflake.client.log;

import static net.snowflake.client.jdbc.SnowflakeUtil.systemGetProperty;

import java.io.IOException;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.*;
import net.snowflake.client.core.EventHandler;
import net.snowflake.client.core.EventUtil;
import net.snowflake.client.util.SecretDetector;

/**
 * Use java.util.logging to implements SFLogger.
 *
 * 

Log Level mapping from SFLogger to java.util.logging: ERROR -- SEVERE WARN -- WARNING INFO -- * INFO DEBUG -- FINE TRACE -- FINEST * *

Created by hyu on 11/17/16. */ public class JDK14Logger implements SFLogger { private Logger jdkLogger; private Set logMethods = new HashSet<>(Arrays.asList("debug", "error", "info", "trace", "warn", "debugNoMask")); private static boolean isLoggerInit = false; public static String STDOUT = "STDOUT"; public JDK14Logger(String name) { this.jdkLogger = Logger.getLogger(name); } public boolean isDebugEnabled() { return this.jdkLogger.isLoggable(Level.FINE); } public boolean isErrorEnabled() { return this.jdkLogger.isLoggable(Level.SEVERE); } public boolean isInfoEnabled() { return this.jdkLogger.isLoggable(Level.INFO); } public boolean isTraceEnabled() { return this.jdkLogger.isLoggable(Level.FINEST); } public boolean isWarnEnabled() { return this.jdkLogger.isLoggable(Level.WARNING); } public void debug(String msg, boolean isMasked) { logInternal(Level.FINE, msg, isMasked); } // This function is used to display unmasked, potentially sensitive log information for internal // regression testing purposes. Do not use otherwise. public void debugNoMask(String msg) { logInternal(Level.FINE, msg, false); } public void debug(String msg, Object... arguments) { logInternal(Level.FINE, msg, arguments); } public void debug(String msg, Throwable t) { logInternal(Level.FINE, msg, t); } public void error(String msg, boolean isMasked) { logInternal(Level.SEVERE, msg, isMasked); } public void error(String msg, Object... arguments) { logInternal(Level.SEVERE, msg, arguments); } public void error(String msg, Throwable t) { logInternal(Level.SEVERE, msg, t); } public void info(String msg, boolean isMasked) { logInternal(Level.INFO, msg, isMasked); } public void info(String msg, Object... arguments) { logInternal(Level.INFO, msg, arguments); } public void info(String msg, Throwable t) { logInternal(Level.INFO, msg, t); } public void trace(String msg, boolean isMasked) { logInternal(Level.FINEST, msg, isMasked); } public void trace(String msg, Object... arguments) { logInternal(Level.FINEST, msg, arguments); } public void trace(String msg, Throwable t) { logInternal(Level.FINEST, msg, t); } public void warn(String msg, boolean isMasked) { logInternal(Level.WARNING, msg, isMasked); } public void warn(String msg, Object... arguments) { logInternal(Level.WARNING, msg, arguments); } public void warn(String msg, Throwable t) { logInternal(Level.WARNING, msg, t); } private void logInternal(Level level, String msg, boolean masked) { if (jdkLogger.isLoggable(level)) { String[] source = findSourceInStack(); jdkLogger.logp( level, source[0], source[1], masked == true ? SecretDetector.maskSecrets(msg) : msg); } } private void logInternal(Level level, String msg, Object... arguments) { if (jdkLogger.isLoggable(level)) { String[] source = findSourceInStack(); String message = ""; try { message = MessageFormat.format(refactorString(msg), evaluateLambdaArgs(arguments)); } catch (IllegalArgumentException e) { message = "Unable to format msg: " + msg; } jdkLogger.logp(level, source[0], source[1], SecretDetector.maskSecrets(message)); } } private void logInternal(Level level, String msg, Throwable t) { // add logger message here if (jdkLogger.isLoggable(level)) { String[] source = findSourceInStack(); jdkLogger.logp(level, source[0], source[1], SecretDetector.maskSecrets(msg), t); } } public static void addHandler(Handler handler) { Logger snowflakeLogger = Logger.getLogger(SFFormatter.CLASS_NAME_PREFIX); snowflakeLogger.addHandler(handler); } public static void removeHandler(Handler handler) { Logger snowflakeLogger = Logger.getLogger(SFFormatter.CLASS_NAME_PREFIX); snowflakeLogger.removeHandler(handler); } public static void setUseParentHandlers(boolean value) { Logger snowflakeLogger = Logger.getLogger(SFFormatter.CLASS_NAME_PREFIX); snowflakeLogger.setUseParentHandlers(value); } public static void setLevel(Level level) { Logger snowflakeLogger = Logger.getLogger(SFFormatter.CLASS_NAME_PREFIX); snowflakeLogger.setLevel(level); } public static Level getLevel() { Logger snowflakeLogger = Logger.getLogger(SFFormatter.CLASS_NAME_PREFIX); return snowflakeLogger.getLevel(); } /** * This is way to enable logging in JDBC through TRACING parameter or sf client config file. * * @param level */ public static synchronized void instantiateLogger(Level level, String logPath) throws IOException { if (!isLoggerInit) { loggerInit(level, logPath); isLoggerInit = true; } } /** * Since we use SLF4J ways of formatting string we need to refactor message string if we have * arguments. For example, in sl4j, this string can be formatted with 2 arguments * *

ex.1: Error happened in {} on {} * *

And if two arguments are provided, error message can be formatted. * *

However, in java.util.logging, to achieve formatted error message, Same string should be * converted to * *

ex.2: Error happened in {0} on {1} * *

Which represented first arguments and second arguments will be replaced in the corresponding * places. * *

This method will convert string in ex.1 to ex.2 */ private String refactorString(String original) { StringBuilder sb = new StringBuilder(); int argCount = 0; for (int i = 0; i < original.length(); i++) { if (original.charAt(i) == '{' && i < original.length() - 1 && original.charAt(i + 1) == '}') { sb.append(String.format("{%d}", argCount)); argCount++; i++; } else { sb.append(original.charAt(i)); } } return sb.toString(); } /** * Used to find the index of the source class/method in current stack This method will locate the * source as the first method after logMethods * * @return an array of size two, first element is className and second is methodName */ private String[] findSourceInStack() { StackTraceElement[] stackTraces = Thread.currentThread().getStackTrace(); String[] results = new String[2]; for (int i = 0; i < stackTraces.length; i++) { if (logMethods.contains(stackTraces[i].getMethodName())) { // since already find the highest logMethods, find the first method after this one // and is not a logMethods. This is done to avoid multiple wrapper over log methods for (int j = i; j < stackTraces.length; j++) { if (!logMethods.contains(stackTraces[j].getMethodName())) { results[0] = stackTraces[j].getClassName(); results[1] = stackTraces[j].getMethodName(); return results; } } } } return results; } private static void loggerInit(Level level, String outputPath) throws IOException { Logger snowflakeLoggerInformaticaV1 = Logger.getLogger(SFFormatter.INFORMATICA_V1_CLASS_NAME_PREFIX); // setup event handler EventHandler eventHandler = EventUtil.getEventHandlerInstance(); eventHandler.setLevel(Level.INFO); eventHandler.setFormatter(new SimpleFormatter()); JDK14Logger.addHandler(eventHandler); snowflakeLoggerInformaticaV1.setLevel(level); JDK14Logger.setLevel(level); snowflakeLoggerInformaticaV1.addHandler(eventHandler); if (STDOUT.equalsIgnoreCase(outputPath)) { // Initialize console handler ConsoleHandler consoleHandler = new ConsoleHandler(); consoleHandler.setLevel(level); consoleHandler.setFormatter(new SFFormatter()); JDK14Logger.addHandler(consoleHandler); snowflakeLoggerInformaticaV1.addHandler(consoleHandler); } else { // Initialize file handler. // get log count and size String defaultLogSizeVal = systemGetProperty("snowflake.jdbc.log.size"); String defaultLogCountVal = systemGetProperty("snowflake.jdbc.log.count"); // default log size to 1 GB int logSize = 1000000000; // default number of log files to rotate to 2 int logCount = 2; if (defaultLogSizeVal != null) { try { logSize = Integer.parseInt(defaultLogSizeVal); } catch (Exception ex) { ; } } if (defaultLogCountVal != null) { try { logCount = Integer.parseInt(defaultLogCountVal); } catch (Exception ex) { ; } } // write log file to tmp directory FileHandler fileHandler = new FileHandler(outputPath, logSize, logCount, true); fileHandler.setFormatter(new SFFormatter()); fileHandler.setLevel(level); JDK14Logger.addHandler(fileHandler); snowflakeLoggerInformaticaV1.addHandler(fileHandler); } } private static Object[] evaluateLambdaArgs(Object... args) { final Object[] result = new Object[args.length]; for (int i = 0; i < args.length; i++) { result[i] = args[i] instanceof ArgSupplier ? ((ArgSupplier) args[i]).get() : args[i]; } return result; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy