1 /* 2 * Copyright (C) 2021 The Android Open Source Project 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 android.car.builtin.util; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.annotation.SystemApi; 22 import android.os.Trace; 23 import android.util.Log; 24 import android.util.Slog; 25 import android.util.TimingsTraceLog; 26 27 import com.android.internal.annotations.GuardedBy; 28 29 import java.util.Formatter; 30 import java.util.Locale; 31 32 /** 33 * Wrapper class for {@code com.android.server.utils.Slogf}. Check the class for API documentation. 34 * 35 * @hide 36 */ 37 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) 38 public final class Slogf { 39 // Entire class copied from {@code com.android.server.utils.Slogf} 40 @GuardedBy("sMessageBuilder") 41 private static final StringBuilder sMessageBuilder; 42 43 @GuardedBy("sMessageBuilder") 44 private static final Formatter sFormatter; 45 46 static { 47 TimingsTraceLog t = new TimingsTraceLog("SLog", Trace.TRACE_TAG_SYSTEM_SERVER); 48 t.traceBegin("static_init"); 49 sMessageBuilder = new StringBuilder(); 50 sFormatter = new Formatter(sMessageBuilder, Locale.ENGLISH); t.traceEnd()51 t.traceEnd(); 52 } 53 54 // Internal log tag only for isLoggable(), the tag will be set to VERBOSE during the car tests. 55 private static final String CAR_TEST_TAG = "CAR.TEST"; 56 Slogf()57 private Slogf() { 58 throw new UnsupportedOperationException("provides only static methods"); 59 } 60 61 /** Same as {@link Log#isLoggable(String, int)}, but also checks for {@code CAR_TEST_TAG}. */ isLoggable(@onNull String tag, int level)62 public static boolean isLoggable(@NonNull String tag, int level) { 63 return Log.isLoggable(tag, level) || Log.isLoggable(CAR_TEST_TAG, Log.VERBOSE); 64 } 65 66 /** Same as {@link Slog#v(String, String)}. */ v(@onNull String tag, @NonNull String msg)67 public static int v(@NonNull String tag, @NonNull String msg) { 68 return Slog.v(tag, msg); 69 } 70 71 /** Same as {@link Slog#v(String, String, Throwable)}. */ v(@onNull String tag, @NonNull String msg, @NonNull Throwable tr)72 public static int v(@NonNull String tag, @NonNull String msg, @NonNull Throwable tr) { 73 return Slog.v(tag, msg, tr); 74 } 75 76 /** Same as {@link Slog#d(String, String)}. */ d(@onNull String tag, @NonNull String msg)77 public static int d(@NonNull String tag, @NonNull String msg) { 78 return Slog.d(tag, msg); 79 } 80 81 /** Same as {@link Slog#d(String, String, Throwable)}. */ d(@onNull String tag, @NonNull String msg, @NonNull Throwable tr)82 public static int d(@NonNull String tag, @NonNull String msg, @NonNull Throwable tr) { 83 return Slog.d(tag, msg, tr); 84 } 85 86 /** Same as {@link Slog#i(String, String)}. */ i(@onNull String tag, @NonNull String msg)87 public static int i(@NonNull String tag, @NonNull String msg) { 88 return Slog.i(tag, msg); 89 } 90 91 /** Same as {@link Slog#i(String, String, Throwable)}. */ i(@onNull String tag, @NonNull String msg, @NonNull Throwable tr)92 public static int i(@NonNull String tag, @NonNull String msg, @NonNull Throwable tr) { 93 return Slog.i(tag, msg, tr); 94 } 95 96 /** Same as {@link Slog#w(String, String)}. */ w(@onNull String tag, @NonNull String msg)97 public static int w(@NonNull String tag, @NonNull String msg) { 98 return Slog.w(tag, msg); 99 } 100 101 /** Same as {@link Slog#w(String, String, Throwable)}. */ w(@onNull String tag, @NonNull String msg, @NonNull Throwable tr)102 public static int w(@NonNull String tag, @NonNull String msg, @NonNull Throwable tr) { 103 return Slog.w(tag, msg, tr); 104 } 105 106 /** Same as {@link Slog#w(String, String)}. */ w(@onNull String tag, @NonNull Throwable tr)107 public static int w(@NonNull String tag, @NonNull Throwable tr) { 108 return Slog.w(tag, tr); 109 } 110 111 /** Same as {@link Slog#e(String, String)}. */ e(@onNull String tag, @NonNull String msg)112 public static int e(@NonNull String tag, @NonNull String msg) { 113 return Slog.e(tag, msg); 114 } 115 116 /** Same as {@link Slog#e(String, String, Throwable)}. */ e(@onNull String tag, @NonNull String msg, @NonNull Throwable tr)117 public static int e(@NonNull String tag, @NonNull String msg, @NonNull Throwable tr) { 118 return Slog.e(tag, msg, tr); 119 } 120 121 /** Same as {@link Slog#wtf(String, String)}. */ wtf(@onNull String tag, @NonNull String msg)122 public static int wtf(@NonNull String tag, @NonNull String msg) { 123 return Slog.wtf(tag, msg); 124 } 125 126 /** Same as {@link Slog#wtf(String, Throwable). */ wtf(@onNull String tag, @NonNull Throwable tr)127 public static int wtf(@NonNull String tag, @NonNull Throwable tr) { 128 return Slog.wtf(tag, tr); 129 } 130 131 /** Same as {@link Slog#wtf(String, String, Throwable)}. */ wtf(@onNull String tag, @NonNull String msg, @NonNull Throwable tr)132 public static int wtf(@NonNull String tag, @NonNull String msg, @NonNull Throwable tr) { 133 return Slog.wtf(tag, msg, tr); 134 } 135 136 /** 137 * Logs a {@link Log.VERBOSE} message. 138 * <p> 139 * <strong>Note: </strong>the message will only be formatted if {@link Log#VERBOSE} logging is 140 * enabled for the given {@code tag}, but the compiler will still create an intermediate array 141 * of the objects for the {@code vargars}, which could affect garbage collection. So, if you're 142 * calling this method in a critical path, make sure to explicitly do the check before calling 143 * it. 144 */ v(@onNull String tag, @NonNull String format, @Nullable Object... args)145 public static void v(@NonNull String tag, @NonNull String format, @Nullable Object... args) { 146 if (!isLoggable(tag, Log.VERBOSE)) return; 147 148 v(tag, getMessage(format, args)); 149 } 150 151 /** 152 * Logs a {@link Log.DEBUG} message. 153 * <p> 154 * <strong>Note: </strong>the message will only be formatted if {@link Log#DEBUG} logging is 155 * enabled for the given {@code tag}, but the compiler will still create an intermediate array 156 * of the objects for the {@code vargars}, which could affect garbage collection. So, if you're 157 * calling this method in a critical path, make sure to explicitly do the check before calling 158 * it. 159 */ d(@onNull String tag, @NonNull String format, @Nullable Object... args)160 public static void d(@NonNull String tag, @NonNull String format, @Nullable Object... args) { 161 if (!isLoggable(tag, Log.DEBUG)) return; 162 163 d(tag, getMessage(format, args)); 164 } 165 166 /** 167 * Logs a {@link Log.INFO} message. 168 * <p> 169 * <strong>Note: </strong>the message will only be formatted if {@link Log#INFO} logging is 170 * enabled for the given {@code tag}, but the compiler will still create an intermediate array 171 * of the objects for the {@code vargars}, which could affect garbage collection. So, if you're 172 * calling this method in a critical path, make sure to explicitly do the check before calling 173 * it. 174 */ i(@onNull String tag, @NonNull String format, @Nullable Object... args)175 public static void i(@NonNull String tag, @NonNull String format, @Nullable Object... args) { 176 if (!isLoggable(tag, Log.INFO)) return; 177 178 i(tag, getMessage(format, args)); 179 } 180 181 /** 182 * Logs a {@link Log.WARN} message. 183 * <p> 184 * <strong>Note: </strong>the message will only be formatted if {@link Log#WARN} logging is 185 * enabled for the given {@code tag}, but the compiler will still create an intermediate array 186 * of the objects for the {@code vargars}, which could affect garbage collection. So, if you're 187 * calling this method in a critical path, make sure to explicitly do the check before calling 188 * it. 189 */ w(@onNull String tag, @NonNull String format, @Nullable Object... args)190 public static void w(@NonNull String tag, @NonNull String format, @Nullable Object... args) { 191 if (!isLoggable(tag, Log.WARN)) return; 192 193 w(tag, getMessage(format, args)); 194 } 195 196 /** 197 * Logs a {@link Log.WARN} message with an exception 198 * <p> 199 * <strong>Note: </strong>the message will only be formatted if {@link Log#WARN} logging is 200 * enabled for the given {@code tag}, but the compiler will still create an intermediate array 201 * of the objects for the {@code vargars}, which could affect garbage collection. So, if you're 202 * calling this method in a critical path, make sure to explicitly do the check before calling 203 * it. 204 */ w(@onNull String tag, @NonNull Exception exception, @NonNull String format, @Nullable Object... args)205 public static void w(@NonNull String tag, @NonNull Exception exception, @NonNull String format, 206 @Nullable Object... args) { 207 if (!isLoggable(tag, Log.WARN)) return; 208 209 w(tag, getMessage(format, args), exception); 210 } 211 212 /** 213 * Logs a {@link Log.ERROR} message. 214 * <p> 215 * <strong>Note: </strong>the message will only be formatted if {@link Log#ERROR} logging is 216 * enabled for the given {@code tag}, but the compiler will still create an intermediate array 217 * of the objects for the {@code vargars}, which could affect garbage collection. So, if you're 218 * calling this method in a critical path, make sure to explicitly do the check before calling 219 * it. 220 */ e(@onNull String tag, @NonNull String format, @Nullable Object... args)221 public static void e(@NonNull String tag, @NonNull String format, @Nullable Object... args) { 222 if (!isLoggable(tag, Log.ERROR)) return; 223 224 e(tag, getMessage(format, args)); 225 } 226 227 /** 228 * Logs a {@link Log.ERROR} message with an exception 229 * <p> 230 * <strong>Note: </strong>the message will only be formatted if {@link Log#ERROR} logging is 231 * enabled for the given {@code tag}, but the compiler will still create an intermediate array 232 * of the objects for the {@code vargars}, which could affect garbage collection. So, if you're 233 * calling this method in a critical path, make sure to explicitly do the check before calling 234 * it. 235 */ e(@onNull String tag, @NonNull Exception exception, @NonNull String format, @Nullable Object... args)236 public static void e(@NonNull String tag, @NonNull Exception exception, @NonNull String format, 237 @Nullable Object... args) { 238 if (!isLoggable(tag, Log.ERROR)) return; 239 240 e(tag, getMessage(format, args), exception); 241 } 242 243 /** 244 * Logs a {@code wtf} message. 245 */ wtf(@onNull String tag, @NonNull String format, @Nullable Object... args)246 public static void wtf(@NonNull String tag, @NonNull String format, @Nullable Object... args) { 247 wtf(tag, getMessage(format, args)); 248 } 249 250 /** 251 * Logs a {@code wtf} message with an exception. 252 */ wtf(@onNull String tag, @NonNull Exception exception, @NonNull String format, @Nullable Object... args)253 public static void wtf(@NonNull String tag, @NonNull Exception exception, 254 @NonNull String format, @Nullable Object... args) { 255 wtf(tag, getMessage(format, args), exception); 256 } 257 getMessage(@onNull String format, @Nullable Object... args)258 private static String getMessage(@NonNull String format, @Nullable Object... args) { 259 synchronized (sMessageBuilder) { 260 sFormatter.format(format, args); 261 String message = sMessageBuilder.toString(); 262 sMessageBuilder.setLength(0); 263 return message; 264 } 265 } 266 } 267