1838414545d9731775fa7d6049f48000f26db88f3Andy Hung/* 2838414545d9731775fa7d6049f48000f26db88f3Andy Hung * Copyright 2017 The Android Open Source Project 3838414545d9731775fa7d6049f48000f26db88f3Andy Hung * 4838414545d9731775fa7d6049f48000f26db88f3Andy Hung * Licensed under the Apache License, Version 2.0 (the "License"); 5838414545d9731775fa7d6049f48000f26db88f3Andy Hung * you may not use this file except in compliance with the License. 6838414545d9731775fa7d6049f48000f26db88f3Andy Hung * You may obtain a copy of the License at 7838414545d9731775fa7d6049f48000f26db88f3Andy Hung * 8838414545d9731775fa7d6049f48000f26db88f3Andy Hung * http://www.apache.org/licenses/LICENSE-2.0 9838414545d9731775fa7d6049f48000f26db88f3Andy Hung * 10838414545d9731775fa7d6049f48000f26db88f3Andy Hung * Unless required by applicable law or agreed to in writing, software 11838414545d9731775fa7d6049f48000f26db88f3Andy Hung * distributed under the License is distributed on an "AS IS" BASIS, 12838414545d9731775fa7d6049f48000f26db88f3Andy Hung * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13838414545d9731775fa7d6049f48000f26db88f3Andy Hung * See the License for the specific language governing permissions and 14838414545d9731775fa7d6049f48000f26db88f3Andy Hung * limitations under the License. 15838414545d9731775fa7d6049f48000f26db88f3Andy Hung */ 16838414545d9731775fa7d6049f48000f26db88f3Andy Hung 17838414545d9731775fa7d6049f48000f26db88f3Andy Hung#ifndef ANDROID_AUDIO_SIMPLE_LOG_H 18838414545d9731775fa7d6049f48000f26db88f3Andy Hung#define ANDROID_AUDIO_SIMPLE_LOG_H 19838414545d9731775fa7d6049f48000f26db88f3Andy Hung 20838414545d9731775fa7d6049f48000f26db88f3Andy Hung#include <deque> 21838414545d9731775fa7d6049f48000f26db88f3Andy Hung#include <mutex> 22838414545d9731775fa7d6049f48000f26db88f3Andy Hung#include <sstream> 23838414545d9731775fa7d6049f48000f26db88f3Andy Hung#include <stdint.h> 24838414545d9731775fa7d6049f48000f26db88f3Andy Hung#include <string> 25838414545d9731775fa7d6049f48000f26db88f3Andy Hung#include <unistd.h> 26838414545d9731775fa7d6049f48000f26db88f3Andy Hung#include <utils/Errors.h> 27838414545d9731775fa7d6049f48000f26db88f3Andy Hung 28838414545d9731775fa7d6049f48000f26db88f3Andy Hung#include <audio_utils/clock.h> 29838414545d9731775fa7d6049f48000f26db88f3Andy Hung 30838414545d9731775fa7d6049f48000f26db88f3Andy Hungnamespace android { 31838414545d9731775fa7d6049f48000f26db88f3Andy Hung 32838414545d9731775fa7d6049f48000f26db88f3Andy Hung/** 33838414545d9731775fa7d6049f48000f26db88f3Andy Hung * SimpleLog provides a private logcat-style logging to avoid cluttering 34838414545d9731775fa7d6049f48000f26db88f3Andy Hung * the device logcat. 35838414545d9731775fa7d6049f48000f26db88f3Andy Hung * 36838414545d9731775fa7d6049f48000f26db88f3Andy Hung * The public methods are internally protected by a mutex to be thread-safe. 37838414545d9731775fa7d6049f48000f26db88f3Andy Hung * Do not call from a sched_fifo thread as it can use a system time call 38838414545d9731775fa7d6049f48000f26db88f3Andy Hung * and obtains a local mutex. 39838414545d9731775fa7d6049f48000f26db88f3Andy Hung * 40838414545d9731775fa7d6049f48000f26db88f3Andy Hung * Formatted logs by log() and logv() will be truncated at kMaxStringLength - 1 41838414545d9731775fa7d6049f48000f26db88f3Andy Hung * due to null termination. logs() does not have a string length limitation. 42838414545d9731775fa7d6049f48000f26db88f3Andy Hung */ 43838414545d9731775fa7d6049f48000f26db88f3Andy Hung 44838414545d9731775fa7d6049f48000f26db88f3Andy Hungclass SimpleLog { 45838414545d9731775fa7d6049f48000f26db88f3Andy Hungpublic: 46838414545d9731775fa7d6049f48000f26db88f3Andy Hung /** 47838414545d9731775fa7d6049f48000f26db88f3Andy Hung * \brief Creates a SimpleLog object. 48838414545d9731775fa7d6049f48000f26db88f3Andy Hung * 49838414545d9731775fa7d6049f48000f26db88f3Andy Hung * \param maxLogLines the maximum number of log lines. 50838414545d9731775fa7d6049f48000f26db88f3Andy Hung */ 51838414545d9731775fa7d6049f48000f26db88f3Andy Hung explicit SimpleLog(size_t maxLogLines = kDefaultMaxLogLines) 52838414545d9731775fa7d6049f48000f26db88f3Andy Hung : mMaxLogLines(maxLogLines) 53838414545d9731775fa7d6049f48000f26db88f3Andy Hung { 54838414545d9731775fa7d6049f48000f26db88f3Andy Hung } 55838414545d9731775fa7d6049f48000f26db88f3Andy Hung 56838414545d9731775fa7d6049f48000f26db88f3Andy Hung /** 57838414545d9731775fa7d6049f48000f26db88f3Andy Hung * \brief Adds a formatted string into the log. 58838414545d9731775fa7d6049f48000f26db88f3Andy Hung * 59838414545d9731775fa7d6049f48000f26db88f3Andy Hung * Time is automatically associated with the string by audio_utils_get_real_time_ns(). 60838414545d9731775fa7d6049f48000f26db88f3Andy Hung * 61838414545d9731775fa7d6049f48000f26db88f3Andy Hung * \param format the format string, similar to printf(). 62838414545d9731775fa7d6049f48000f26db88f3Andy Hung * 63838414545d9731775fa7d6049f48000f26db88f3Andy Hung * and optional arguments. 64838414545d9731775fa7d6049f48000f26db88f3Andy Hung */ 65838414545d9731775fa7d6049f48000f26db88f3Andy Hung // using C++11 unified attribute syntax; index is offset by 1 for implicit "this". 66838414545d9731775fa7d6049f48000f26db88f3Andy Hung [[gnu::format(printf, 2 /* string-index */, 3 /* first-to-check */)]] 67838414545d9731775fa7d6049f48000f26db88f3Andy Hung void log(const char *format, ...) 68838414545d9731775fa7d6049f48000f26db88f3Andy Hung { 69838414545d9731775fa7d6049f48000f26db88f3Andy Hung va_list args; 70838414545d9731775fa7d6049f48000f26db88f3Andy Hung va_start(args, format); 71838414545d9731775fa7d6049f48000f26db88f3Andy Hung // use -1 to trigger the clock fetch within the mutex lock. 72838414545d9731775fa7d6049f48000f26db88f3Andy Hung logv(-1 /* nowNs */, format, args); 73838414545d9731775fa7d6049f48000f26db88f3Andy Hung va_end(args); 74838414545d9731775fa7d6049f48000f26db88f3Andy Hung } 75838414545d9731775fa7d6049f48000f26db88f3Andy Hung 76838414545d9731775fa7d6049f48000f26db88f3Andy Hung /** 77838414545d9731775fa7d6049f48000f26db88f3Andy Hung * \brief Adds a formatted string into the log with time. 78838414545d9731775fa7d6049f48000f26db88f3Andy Hung * 79838414545d9731775fa7d6049f48000f26db88f3Andy Hung * \param nowNs the time to use for logging. Assumed to be monotonically 80838414545d9731775fa7d6049f48000f26db88f3Andy Hung * increasing for sequential calls. If -1, then 81838414545d9731775fa7d6049f48000f26db88f3Andy Hung * audio_utils_get_real_time_ns() is called. 82838414545d9731775fa7d6049f48000f26db88f3Andy Hung * \param format the format string, similar to printf(). 83838414545d9731775fa7d6049f48000f26db88f3Andy Hung * 84838414545d9731775fa7d6049f48000f26db88f3Andy Hung * and optional arguments. 85838414545d9731775fa7d6049f48000f26db88f3Andy Hung */ 86838414545d9731775fa7d6049f48000f26db88f3Andy Hung // using C++11 unified attribute syntax; index is offset by 1 for implicit "this". 87838414545d9731775fa7d6049f48000f26db88f3Andy Hung [[gnu::format(printf, 3 /* string-index */, 4 /* first-to-check */)]] 88838414545d9731775fa7d6049f48000f26db88f3Andy Hung void log(int64_t nowNs, const char *format, ...) 89838414545d9731775fa7d6049f48000f26db88f3Andy Hung { 90838414545d9731775fa7d6049f48000f26db88f3Andy Hung va_list args; 91838414545d9731775fa7d6049f48000f26db88f3Andy Hung va_start(args, format); 92838414545d9731775fa7d6049f48000f26db88f3Andy Hung logv(nowNs, format, args); 93838414545d9731775fa7d6049f48000f26db88f3Andy Hung va_end(args); 94838414545d9731775fa7d6049f48000f26db88f3Andy Hung } 95838414545d9731775fa7d6049f48000f26db88f3Andy Hung 96838414545d9731775fa7d6049f48000f26db88f3Andy Hung /** 97838414545d9731775fa7d6049f48000f26db88f3Andy Hung * \brief Adds a formatted string by va_list with time. Not intended for typical use. 98838414545d9731775fa7d6049f48000f26db88f3Andy Hung * 99838414545d9731775fa7d6049f48000f26db88f3Andy Hung * \param nowNs the time to use for logging. Assumed to be monotonically 100838414545d9731775fa7d6049f48000f26db88f3Andy Hung * increasing for sequential calls. If -1, then 101838414545d9731775fa7d6049f48000f26db88f3Andy Hung * audio_utils_get_real_time_ns() is called. 102838414545d9731775fa7d6049f48000f26db88f3Andy Hung * \param format the format string, similar to printf(). 103838414545d9731775fa7d6049f48000f26db88f3Andy Hung * \param args va_list args. 104838414545d9731775fa7d6049f48000f26db88f3Andy Hung */ 105838414545d9731775fa7d6049f48000f26db88f3Andy Hung void logv(int64_t nowNs, const char *format, va_list args) 106838414545d9731775fa7d6049f48000f26db88f3Andy Hung { 107838414545d9731775fa7d6049f48000f26db88f3Andy Hung // format to buffer 108838414545d9731775fa7d6049f48000f26db88f3Andy Hung char buffer[kMaxStringLength]; 109838414545d9731775fa7d6049f48000f26db88f3Andy Hung int length = vsnprintf(buffer, sizeof(buffer), format, args); 110838414545d9731775fa7d6049f48000f26db88f3Andy Hung if (length < 0) { // encoding error 111838414545d9731775fa7d6049f48000f26db88f3Andy Hung logs(nowNs, "invalid format"); 112838414545d9731775fa7d6049f48000f26db88f3Andy Hung return; 113838414545d9731775fa7d6049f48000f26db88f3Andy Hung } else if (length >= (signed)sizeof(buffer)) { 114838414545d9731775fa7d6049f48000f26db88f3Andy Hung length = sizeof(buffer) - 1; 115838414545d9731775fa7d6049f48000f26db88f3Andy Hung } 116838414545d9731775fa7d6049f48000f26db88f3Andy Hung 117838414545d9731775fa7d6049f48000f26db88f3Andy Hung // strip out trailing newlines 118838414545d9731775fa7d6049f48000f26db88f3Andy Hung while (length > 0 && buffer[length - 1] == '\n') { 119838414545d9731775fa7d6049f48000f26db88f3Andy Hung buffer[--length] = '\0'; 120838414545d9731775fa7d6049f48000f26db88f3Andy Hung } 121838414545d9731775fa7d6049f48000f26db88f3Andy Hung logs(nowNs, buffer); 122838414545d9731775fa7d6049f48000f26db88f3Andy Hung } 123838414545d9731775fa7d6049f48000f26db88f3Andy Hung 124838414545d9731775fa7d6049f48000f26db88f3Andy Hung /** 125838414545d9731775fa7d6049f48000f26db88f3Andy Hung * \brief Logs a string to the buffer with time. 126838414545d9731775fa7d6049f48000f26db88f3Andy Hung * \param nowNs the time to use for logging. Assumed to be monotonically 127838414545d9731775fa7d6049f48000f26db88f3Andy Hung * increasing for sequential calls. If -1, then 128838414545d9731775fa7d6049f48000f26db88f3Andy Hung * audio_utils_get_real_time_ns() is called. 129838414545d9731775fa7d6049f48000f26db88f3Andy Hung * \param buffer contains a null terminated string, which may have 130838414545d9731775fa7d6049f48000f26db88f3Andy Hung * special characters such as % and \ that are 131838414545d9731775fa7d6049f48000f26db88f3Andy Hung * not interpreted. 132838414545d9731775fa7d6049f48000f26db88f3Andy Hung */ 133838414545d9731775fa7d6049f48000f26db88f3Andy Hung void logs(int64_t nowNs, const char *buffer) 134838414545d9731775fa7d6049f48000f26db88f3Andy Hung { 135838414545d9731775fa7d6049f48000f26db88f3Andy Hung // store in circular array 136838414545d9731775fa7d6049f48000f26db88f3Andy Hung std::lock_guard<std::mutex> guard(mLock); 137838414545d9731775fa7d6049f48000f26db88f3Andy Hung if (nowNs == -1) { 138838414545d9731775fa7d6049f48000f26db88f3Andy Hung nowNs = audio_utils_get_real_time_ns(); 139838414545d9731775fa7d6049f48000f26db88f3Andy Hung } 140838414545d9731775fa7d6049f48000f26db88f3Andy Hung mLog.emplace_back(nowNs, std::string(buffer)); 141838414545d9731775fa7d6049f48000f26db88f3Andy Hung if (mLog.size() > mMaxLogLines) { 142838414545d9731775fa7d6049f48000f26db88f3Andy Hung mLog.pop_front(); 143838414545d9731775fa7d6049f48000f26db88f3Andy Hung } 144838414545d9731775fa7d6049f48000f26db88f3Andy Hung } 145838414545d9731775fa7d6049f48000f26db88f3Andy Hung 146838414545d9731775fa7d6049f48000f26db88f3Andy Hung /** 147838414545d9731775fa7d6049f48000f26db88f3Andy Hung * \brief Dumps the log to a string. 148838414545d9731775fa7d6049f48000f26db88f3Andy Hung * 149838414545d9731775fa7d6049f48000f26db88f3Andy Hung * \param prefix the prefix to use for each line 150838414545d9731775fa7d6049f48000f26db88f3Andy Hung * (generally a null terminated string of spaces). 151838414545d9731775fa7d6049f48000f26db88f3Andy Hung * \param lines maximum number of lines to output (0 disables). 152838414545d9731775fa7d6049f48000f26db88f3Andy Hung * \param limitNs limit dump to data more recent than limitNs (0 disables). 153838414545d9731775fa7d6049f48000f26db88f3Andy Hung * \return a string object for the log. 154838414545d9731775fa7d6049f48000f26db88f3Andy Hung */ 155838414545d9731775fa7d6049f48000f26db88f3Andy Hung std::string dumpToString(const char *prefix = "", size_t lines = 0, int64_t limitNs = 0) const 156838414545d9731775fa7d6049f48000f26db88f3Andy Hung { 157838414545d9731775fa7d6049f48000f26db88f3Andy Hung if (lines == 0) { 158838414545d9731775fa7d6049f48000f26db88f3Andy Hung lines = mLog.size(); 159838414545d9731775fa7d6049f48000f26db88f3Andy Hung } 160838414545d9731775fa7d6049f48000f26db88f3Andy Hung 161838414545d9731775fa7d6049f48000f26db88f3Andy Hung std::stringstream ss; 162838414545d9731775fa7d6049f48000f26db88f3Andy Hung std::lock_guard<std::mutex> guard(mLock); 163838414545d9731775fa7d6049f48000f26db88f3Andy Hung auto it = mLog.begin(); 164838414545d9731775fa7d6049f48000f26db88f3Andy Hung 165838414545d9731775fa7d6049f48000f26db88f3Andy Hung // Note: this restricts the lines before checking the time constraint. 166838414545d9731775fa7d6049f48000f26db88f3Andy Hung if (mLog.size() > lines) { 167838414545d9731775fa7d6049f48000f26db88f3Andy Hung it += (mLog.size() - lines); 168838414545d9731775fa7d6049f48000f26db88f3Andy Hung } 169838414545d9731775fa7d6049f48000f26db88f3Andy Hung for (; it != mLog.end(); ++it) { 170838414545d9731775fa7d6049f48000f26db88f3Andy Hung const int64_t time = it->first; 171838414545d9731775fa7d6049f48000f26db88f3Andy Hung if (time < limitNs) continue; // too old 172c1eb186fc1ab8837e95e01be8a87a77e952fc81fAndy Hung ss << prefix << audio_utils_time_string_from_ns(time).time 173c1eb186fc1ab8837e95e01be8a87a77e952fc81fAndy Hung << " " << it->second.c_str() << "\n"; 174838414545d9731775fa7d6049f48000f26db88f3Andy Hung } 175838414545d9731775fa7d6049f48000f26db88f3Andy Hung return ss.str(); 176838414545d9731775fa7d6049f48000f26db88f3Andy Hung } 177838414545d9731775fa7d6049f48000f26db88f3Andy Hung 178838414545d9731775fa7d6049f48000f26db88f3Andy Hung /** 179838414545d9731775fa7d6049f48000f26db88f3Andy Hung * \brief Dumps the log to a raw file descriptor. 180838414545d9731775fa7d6049f48000f26db88f3Andy Hung * 181838414545d9731775fa7d6049f48000f26db88f3Andy Hung * \param fd file descriptor to use. 182838414545d9731775fa7d6049f48000f26db88f3Andy Hung * \param prefix the prefix to use for each line 183838414545d9731775fa7d6049f48000f26db88f3Andy Hung * (generally a null terminated string of spaces). 184838414545d9731775fa7d6049f48000f26db88f3Andy Hung * \param lines maximum number of lines to output (0 disables). 185838414545d9731775fa7d6049f48000f26db88f3Andy Hung * \param limitNs limit dump to data more recent than limitNs (0 disables). 186838414545d9731775fa7d6049f48000f26db88f3Andy Hung * \return 187838414545d9731775fa7d6049f48000f26db88f3Andy Hung * NO_ERROR on success or a negative number (-errno) on failure of write(). 188838414545d9731775fa7d6049f48000f26db88f3Andy Hung */ 189838414545d9731775fa7d6049f48000f26db88f3Andy Hung status_t dump(int fd, const char *prefix = "", size_t lines = 0, int64_t limitNs = 0) const 190838414545d9731775fa7d6049f48000f26db88f3Andy Hung { 191838414545d9731775fa7d6049f48000f26db88f3Andy Hung // dumpToString() and write() are individually thread-safe, but concurrent threads 192838414545d9731775fa7d6049f48000f26db88f3Andy Hung // using dump() to the same file descriptor may write out of order. 193838414545d9731775fa7d6049f48000f26db88f3Andy Hung const std::string s = dumpToString(prefix, lines, limitNs); 194838414545d9731775fa7d6049f48000f26db88f3Andy Hung if (s.size() > 0 && write(fd, s.c_str(), s.size()) < 0) { 195838414545d9731775fa7d6049f48000f26db88f3Andy Hung return -errno; 196838414545d9731775fa7d6049f48000f26db88f3Andy Hung } 197838414545d9731775fa7d6049f48000f26db88f3Andy Hung return NO_ERROR; 198838414545d9731775fa7d6049f48000f26db88f3Andy Hung } 199838414545d9731775fa7d6049f48000f26db88f3Andy Hung 200838414545d9731775fa7d6049f48000f26db88f3Andy Hungprivate: 201838414545d9731775fa7d6049f48000f26db88f3Andy Hung mutable std::mutex mLock; 202838414545d9731775fa7d6049f48000f26db88f3Andy Hung static const size_t kMaxStringLength = 1024; // maximum formatted string length 203838414545d9731775fa7d6049f48000f26db88f3Andy Hung static const size_t kDefaultMaxLogLines = 80; // default maximum log history 204838414545d9731775fa7d6049f48000f26db88f3Andy Hung 205838414545d9731775fa7d6049f48000f26db88f3Andy Hung const size_t mMaxLogLines; // maximum log history 206838414545d9731775fa7d6049f48000f26db88f3Andy Hung std::deque<std::pair<int64_t, std::string>> mLog; // circular buffer is backed by deque. 207838414545d9731775fa7d6049f48000f26db88f3Andy Hung}; 208838414545d9731775fa7d6049f48000f26db88f3Andy Hung 209838414545d9731775fa7d6049f48000f26db88f3Andy Hung} // namespace android 210838414545d9731775fa7d6049f48000f26db88f3Andy Hung 211838414545d9731775fa7d6049f48000f26db88f3Andy Hung#endif // !ANDROID_AUDIO_SIMPLE_LOG_H 212