1 /* 2 * Copyright 2020 The gRPC Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package io.grpc.xds; 18 19 import com.google.common.base.Preconditions; 20 import io.grpc.InternalLogId; 21 import java.text.MessageFormat; 22 import java.util.logging.Level; 23 import java.util.logging.LogRecord; 24 import java.util.logging.Logger; 25 26 /** 27 * An xDS-specific logger for collecting xDS specific events. Information logged here goes 28 * to the Java logger of this class. 29 */ 30 final class XdsLogger { 31 private static final Logger logger = Logger.getLogger(XdsLogger.class.getName()); 32 33 private final String prefix; 34 withLogId(InternalLogId logId)35 static XdsLogger withLogId(InternalLogId logId) { 36 Preconditions.checkNotNull(logId, "logId"); 37 return new XdsLogger(logId.toString()); 38 } 39 withPrefix(String prefix)40 static XdsLogger withPrefix(String prefix) { 41 return new XdsLogger(prefix); 42 } 43 XdsLogger(String prefix)44 private XdsLogger(String prefix) { 45 this.prefix = Preconditions.checkNotNull(prefix, "prefix"); 46 } 47 isLoggable(XdsLogLevel level)48 boolean isLoggable(XdsLogLevel level) { 49 Level javaLevel = toJavaLogLevel(level); 50 return logger.isLoggable(javaLevel); 51 } 52 log(XdsLogLevel level, String msg)53 void log(XdsLogLevel level, String msg) { 54 Level javaLevel = toJavaLogLevel(level); 55 logOnly(prefix, javaLevel, msg); 56 } 57 log(XdsLogLevel level, String messageFormat, Object... args)58 void log(XdsLogLevel level, String messageFormat, Object... args) { 59 Level javaLogLevel = toJavaLogLevel(level); 60 if (logger.isLoggable(javaLogLevel)) { 61 String msg = MessageFormat.format(messageFormat, args); 62 logOnly(prefix, javaLogLevel, msg); 63 } 64 } 65 logOnly(String prefix, Level logLevel, String msg)66 private static void logOnly(String prefix, Level logLevel, String msg) { 67 if (logger.isLoggable(logLevel)) { 68 LogRecord lr = new LogRecord(logLevel, "[" + prefix + "] " + msg); 69 // No resource bundle as gRPC is not localized. 70 lr.setLoggerName(logger.getName()); 71 lr.setSourceClassName(logger.getName()); 72 lr.setSourceMethodName("log"); 73 logger.log(lr); 74 } 75 } 76 toJavaLogLevel(XdsLogLevel level)77 private static Level toJavaLogLevel(XdsLogLevel level) { 78 switch (level) { 79 case ERROR: 80 case WARNING: 81 return Level.FINE; 82 case INFO: 83 return Level.FINER; 84 case FORCE_INFO: 85 return Level.INFO; 86 case FORCE_WARNING: 87 return Level.WARNING; 88 default: 89 return Level.FINEST; 90 } 91 } 92 93 /** 94 * Log levels. See the table below for the mapping from the XdsLogger levels to 95 * Java logger levels. 96 * 97 * <p><b>NOTE:</b> 98 * Please use {@code FORCE_} levels with care, only when the message is expected to be 99 * surfaced to the library user. Normally libraries should minimize the usage 100 * of highly visible logs. 101 * <pre> 102 * +---------------------+-------------------+ 103 * | XdsLogger Level | Java Logger Level | 104 * +---------------------+-------------------+ 105 * | DEBUG | FINEST | 106 * | INFO | FINER | 107 * | WARNING | FINE | 108 * | ERROR | FINE | 109 * | FORCE_INFO | INFO | 110 * | FORCE_WARNING | WARNING | 111 * +---------------------+-------------------+ 112 * </pre> 113 */ 114 enum XdsLogLevel { 115 DEBUG, 116 INFO, 117 WARNING, 118 ERROR, 119 FORCE_INFO, 120 FORCE_WARNING, 121 } 122 } 123