1 /*
2  * Copyright (C) 2022 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 com.android.libraries.pcc.chronicle.util
18 
19 import android.util.Log
20 import android.util.Log.DEBUG
21 import android.util.Log.ERROR
22 import android.util.Log.INFO
23 import android.util.Log.VERBOSE
24 import android.util.Log.WARN
25 
26 /** Container for Chronicle's loggers. */
27 object Logcat {
28   private const val DEFAULT_TAG: String = "Chronicle"
29   private const val CLIENT_TAG: String = "ChronicleClient"
30   private const val SERVER_TAG: String = "ChronicleServer"
31 
32   /**
33    * [TaggedLogger] intended for use by implementations of the Chronicle interface and as a
34    * catch-all in situations where it doesn't make sense to implement a new logger.
35    */
36   val default: TaggedLogger = TaggedLogger(DEFAULT_TAG)
37 
38   /** [TaggedLogger] intended for use by client-side API components. */
39   val clientSide: TaggedLogger = TaggedLogger(CLIENT_TAG)
40 
41   /** [TaggedLogger] intended for use by server-side API components. */
42   val serverSide: TaggedLogger = TaggedLogger(SERVER_TAG)
43 }
44 
45 /**
46  * Helper class to associate a tag with logging calls. Each method simply calls the corresponding
47  * method in Android's native logger with the given tag.
48  */
49 class TaggedLogger(val tag: String) {
50 
51   /**
52    * Send a [VERBOSE] log message.
53    * @param msg The message you would like logged.
54    */
vnull55   fun v(msg: String, vararg args: Any) {
56     if (Log.isLoggable(tag, VERBOSE)) {
57       Log.v(tag, String.format(msg, *args))
58     }
59   }
60 
61   /**
62    * Send a [VERBOSE] log message and log the exception.
63    * @param tr An exception to log
64    * @param msg The message you would like logged.
65    */
vnull66   fun v(tr: Throwable, msg: String, vararg args: Any) {
67     if (Log.isLoggable(tag, VERBOSE)) {
68       Log.v(tag, String.format(msg, *args), tr)
69     }
70   }
71 
72   /**
73    * Send a [DEBUG] log message.
74    * @param msg The message you would like logged.
75    */
dnull76   fun d(msg: String, vararg args: Any) {
77     if (Log.isLoggable(tag, DEBUG)) {
78       Log.d(tag, String.format(msg, *args))
79     }
80   }
81 
82   /**
83    * Send a [DEBUG] log message and log the exception.
84    * @param tr An exception to log
85    * @param msg The message you would like logged.
86    */
dnull87   fun d(tr: Throwable, msg: String, vararg args: Any) {
88     if (Log.isLoggable(tag, DEBUG)) {
89       Log.d(tag, String.format(msg, *args), tr)
90     }
91   }
92 
93   /**
94    * Send an [INFO] log message.
95    * @param msg The message you would like logged.
96    */
inull97   fun i(msg: String, vararg args: Any) {
98     if (Log.isLoggable(tag, INFO)) {
99       Log.i(tag, String.format(msg, *args))
100     }
101   }
102 
103   /**
104    * Send a [INFO] log message and log the exception.
105    * @param tr An exception to log
106    * @param msg The message you would like logged.
107    */
inull108   fun i(tr: Throwable, msg: String, vararg args: Any) {
109     if (Log.isLoggable(tag, INFO)) {
110       Log.i(tag, String.format(msg, *args), tr)
111     }
112   }
113 
114   /**
115    * Send a [WARN] log message.
116    * @param msg The message you would like logged.
117    */
wnull118   fun w(msg: String, vararg args: Any) {
119     if (Log.isLoggable(tag, WARN)) {
120       Log.w(tag, String.format(msg, *args))
121     }
122   }
123 
124   /**
125    * Send a [WARN] log message and log the exception.
126    * @param tr An exception to log
127    * @param msg The message you would like logged.
128    */
wnull129   fun w(tr: Throwable, msg: String, vararg args: Any) {
130     if (Log.isLoggable(tag, WARN)) {
131       Log.w(tag, String.format(msg, *args), tr)
132     }
133   }
134 
135   /**
136    * Send a [WARN] log message and log the exception.
137    * @param tr An exception to log
138    */
wnull139   fun w(tr: Throwable) {
140     if (Log.isLoggable(tag, WARN)) {
141       Log.w(tag, tr)
142     }
143   }
144 
145   /**
146    * Send an [ERROR] log message.
147    * @param msg The message you would like logged.
148    */
enull149   fun e(msg: String, vararg args: Any) {
150     if (Log.isLoggable(tag, ERROR)) {
151       Log.e(tag, String.format(msg, *args))
152     }
153   }
154 
155   /**
156    * Send a [ERROR] log message and log the exception.
157    * @param tr An exception to log
158    * @param msg The message you would like logged.
159    */
enull160   fun e(tr: Throwable, msg: String, vararg args: Any) {
161     if (Log.isLoggable(tag, ERROR)) {
162       Log.e(tag, String.format(msg, *args), tr)
163     }
164   }
165 
166   /**
167    * Handy function to get a loggable stack trace from a Throwable
168    * @param tr An exception to log
169    */
getStackTraceStringnull170   fun getStackTraceString(tr: Throwable): String {
171     return Log.getStackTraceString(tr)
172   }
173 
174   /**
175    * Low-level logging call.
176    * @param priority The priority/type of this log message
177    * @param msg The message you would like logged.
178    * @return The number of bytes written.
179    */
printlnnull180   fun println(priority: Int, msg: String, vararg args: Any) {
181     if (Log.isLoggable(tag, priority)) {
182       Log.println(priority, tag, String.format(msg, *args))
183     }
184   }
185 
186   /**
187    * Times the duration of the [block] and logs the provided [message] along with the duration at
188    * [VERBOSE] level.
189    */
timeVerbosenull190   inline fun <T> timeVerbose(message: String, block: () -> T): T {
191     val start = System.nanoTime()
192     return try {
193       block()
194     } finally {
195       val duration = System.nanoTime() - start
196       v("%s [duration: %.3f ms]", message, duration / 1000000.0)
197     }
198   }
199 }
200