xref: /aosp_15_r20/external/gmmlib/Source/GmmLib/Utility/GmmLog/GmmLog.cpp (revision 35ffd701415c9e32e53136d61a677a8d0a8fc4a5)
1 /*==============================================================================
2 Copyright(c) 2017 Intel Corporation
3 
4 Permission is hereby granted, free of charge, to any person obtaining a
5 copy of this software and associated documentation files(the "Software"),
6 to deal in the Software without restriction, including without limitation
7 the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 and / or sell copies of the Software, and to permit persons to whom the
9 Software is furnished to do so, subject to the following conditions:
10 
11 The above copyright notice and this permission notice shall be included
12 in all copies or substantial portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 OTHER DEALINGS IN THE SOFTWARE.
21 ============================================================================*/
22 
23 #include "GmmLog.h"
24 
25 #if GMM_LOG_AVAILABLE
26 #include "Internal/Common/GmmLibInc.h"
27 #include "Internal/Common/GmmLogger.h"
28 
29 #if _WIN32
30 #include <process.h>
31 #include <memory>
32 #else
33 #include <stdio.h>
34 #include <sys/stat.h>
35 #include <unistd.h>
36 #include <fstream>
37 #include <linux/limits.h>
38 #endif
39 
40 /// Logger instance shared by all of GmmLib within a process
41 #if(_DEBUG || _RELEASE_INTERNAL)
42 GmmLib::Logger &GmmLoggerPerProc = GmmLib::Logger::CreateGmmLogSingleton();
43 #endif
44 
45 #if _WIN32
46 namespace spdlog
47 {
48     namespace sinks
49     {
50         /////////////////////////////////////////////////////////////////////////////////////
51         /// class defines a sink which prints the messages to the debugger
52         /////////////////////////////////////////////////////////////////////////////////////
53         class Debugger : public sink
54         {
log(const details::log_msg & msg)55             void log(const details::log_msg &msg) override
56             {
57                 OutputDebugString(GMM_PREFIX_STR);
58                 OutputDebugString(msg.formatted.str().c_str());
59             }
60 
flush()61             void flush()
62             {
63             }
64         };
65     }
66 }
67 #endif
68 
69 /////////////////////////////////////////////////////////////////////////////////////
70 /// Initializes Gmm Logger
71 ///
72 /// @return     true if initialized successfully. false otherwise
73 /////////////////////////////////////////////////////////////////////////////////////
GmmLogInit()74 bool GmmLib::Logger::GmmLogInit()
75 {
76     std::string LogFilePath;
77     std::string ProcPath;
78     std::string ProcName;
79     int         Pid = 0;
80 
81 // Get logging method
82 #if _WIN32
83     uint32_t regkeyVal = 0;
84     if(Utility::GmmUMDReadRegistryFullPath(GMM_LOG_REG_KEY_SUB_PATH, GMM_LOG_TO_FILE, &regkeyVal))
85     {
86         LogMethod = regkeyVal ? ToFile : ToOSLog;
87     }
88 
89     if(Utility::GmmUMDReadRegistryFullPath(GMM_LOG_REG_KEY_SUB_PATH, GMM_LOG_LEVEL_REGKEY, &regkeyVal))
90     {
91         switch(static_cast<GmmLogLevel>(regkeyVal))
92         {
93             case Trace:
94                 LogLevel = spdlog::level::trace;
95                 break;
96             case Info:
97                 LogLevel = spdlog::level::info;
98                 break;
99             case Error:
100                 LogLevel = spdlog::level::err;
101                 break;
102 	    case Critical:
103 		LogLevel = spdlog::level::critical;
104                 break;
105             case Off:
106             default:
107                 LogLevel = spdlog::level::off;
108                 break;
109 	}
110     }
111 
112 #endif
113     if(LogLevel == spdlog::level::off)
114     {
115         return false;
116     }
117 
118     try
119     {
120         if(LogMethod == ToFile)
121         {
122 // Get process name
123 #if _WIN32
124             TCHAR ProcPathTChar[MAX_PATH];
125             GetModuleFileName(NULL, ProcPathTChar, MAX_PATH);
126             ProcPath = std::string(ProcPathTChar);
127 
128             size_t PosOfLastSlash = ProcPath.find_last_of("\\") + 1;
129             size_t PosOfLastDot   = ProcPath.find_last_of(".");
130 
131             if(PosOfLastDot <= PosOfLastSlash || PosOfLastDot >= ProcPath.length() || PosOfLastSlash >= ProcPath.length())
132             {
133                 ProcName = GMM_UNKNOWN_PROCESS;
134             }
135             else
136             {
137                 ProcName = ProcPath.substr(PosOfLastSlash, PosOfLastDot - PosOfLastSlash);
138             }
139 #else
140             ProcPath = "Unknown_Proc_Path";
141             ProcName = GMM_UNKNOWN_PROCESS;
142 
143             std::ifstream file;
144             file.open("/proc/self/cmdline");
145             if(file.is_open())
146             {
147                 // Get process name
148                 getline(file, ProcPath);
149 
150                 size_t PosOfLastSlash = ProcPath.find_last_of("/") + 1;
151                 if(PosOfLastSlash >= ProcPath.length())
152                 {
153                     ProcName = GMM_UNKNOWN_PROCESS;
154                 }
155                 else
156                 {
157                     // "length-1" to remove null character
158                     ProcName = ProcPath.substr(PosOfLastSlash, ProcPath.length() - 1);
159                 }
160 
161                 file.close();
162             }
163 
164 #endif
165 
166 // Get process ID
167 #if _WIN32
168             Pid = _getpid();
169 #else
170             Pid = getpid();
171 #endif
172             std::string PidStr = std::to_string(Pid);
173 
174             // TODO: Multiple GmmLib instance can be running in the same process. In that case, the file name will be
175             // the same for two instances. Figure out a way to differentiate between the two instances.
176 #if _WIN32
177 	    LogFilePath = std::string("c:\\") + std::string(GMM_LOG_FILENAME) + "_" + ProcName + "_" + PidStr;
178 #else
179 	    LogFilePath = std::string(".//") + std::string(GMM_LOG_FILENAME) + "" + ProcName + "_" + PidStr;
180 #endif
181             // Create logger
182             SpdLogger = spdlog::rotating_logger_mt(GMM_LOGGER_NAME,
183                                                    LogFilePath,
184                                                    GMM_LOG_FILE_SIZE,
185                                                    GMM_ROTATE_FILE_NUMBER);
186 
187             // Log process path
188             SpdLogger->set_pattern("Process path: %v");
189             SpdLogger->info(ProcPath.c_str());
190         }
191         else
192         {
193 #if defined(_WIN32)
194             // Log to debugger
195             auto debugger_sink = std::make_shared<spdlog::sinks::Debugger>();
196             SpdLogger          = std::make_shared<spdlog::logger>(GMM_LOGGER_NAME, debugger_sink);
197 #elif defined(__ANDROID__)
198             // Log to logcat
199             SpdLogger   = spdlog::android_logger(GMM_LOGGER_NAME, GMM_LOG_TAG);
200 #elif defined(__linux__)
201             // Log to syslog
202             SpdLogger = spdlog::syslog_logger(GMM_LOGGER_NAME, GMM_LOG_TAG, 1 /*Log Pid*/);
203 #else
204             __GMM_ASSERT(0);
205             return false;
206 #endif
207         }
208     }
209     catch(const spdlog::spdlog_ex &ex)
210     {
211         __GMM_ASSERT(0);
212         return false;
213     }
214 
215     // Set log level
216     SpdLogger->set_level(LogLevel);
217     // Set log pattern
218     SpdLogger->set_pattern("[%T.%e] [Thread %t] [%l] %v"); // [Time] [Thread id] [Log Level] [Text to Log]
219 
220     return true;
221 }
222 
223 /////////////////////////////////////////////////////////////////////////////////////
224 /// Gmm Logger constructor
225 /////////////////////////////////////////////////////////////////////////////////////
Logger()226 GmmLib::Logger::Logger()
227     : LogMethod(ToOSLog),
228       LogLevel(spdlog::level::off)
229 {
230     if(!GmmLogInit())
231     {
232         spdlog::set_level(spdlog::level::off);
233     }
234 }
235 
236 /////////////////////////////////////////////////////////////////////////////////////
237 /// Gmm Logger Destructor
238 /////////////////////////////////////////////////////////////////////////////////////
~Logger()239 GmmLib::Logger::~Logger()
240 {
241     if(SpdLogger)
242     {
243         SpdLogger->flush();
244     }
245 }
246 
247 /////////////////////////////////////////////////////////////////////////////////////
248 /// Gmm Logger C wrappers
249 /////////////////////////////////////////////////////////////////////////////////////
250 #if !_WIN32
251 // Linux/Android replacement for MS version of _vscprintf
vscprintf_lin(const char * msg,va_list args)252 inline int vscprintf_lin(const char *msg, va_list args)
253 {
254     char    c;
255     va_list args_cpy;
256 
257     // Copy `args' to prevent internal pointer modification from vsnprintf
258     va_copy(args_cpy, args);
259     int len = vsnprintf(&c, 1, msg, args_cpy);
260     va_end(args_cpy);
261     return len;
262 }
263 #endif
264 
265 /////////////////////////////////////////////////////////////////////////////////////
266 /// Gmm Logger C wrapper for GMM_LOG_* Macros
267 /////////////////////////////////////////////////////////////////////////////////////
GmmLibLogging(GmmLogLevel Level,const char * str,...)268 extern "C" void GMM_STDCALL GmmLibLogging(GmmLogLevel Level, const char *str, ...)
269 {
270    va_list args;
271 
272     if(GmmLoggerPerProc.SpdLogger)
273     {
274         va_start(args, str);
275 
276 #if _WIN32
277         const size_t length = _vscprintf(str, args);
278 #else
279         const size_t length = vscprintf_lin(str, args);
280 #endif
281 
282         char *temp = new char[length + 1];
283 
284         if(temp)
285         {
286 
287 #if _WIN32
288             vsprintf_s(temp, length + 1, str, args);
289 #else
290             vsnprintf(temp, length + 1, str, args);
291 #endif
292 
293             switch(Level)
294             {
295                 case Trace:
296                     // Set log level to trace if we want trace msges to be printed
297                     //GmmLoggerPerProc.SpdLogger->set_level(spdlog::level::trace);
298                     GmmLoggerPerProc.SpdLogger->trace(temp);
299                     break;
300                 case Info:
301                     // Set log level to info if we want info msges to be printed
302                     //GmmLoggerPerProc.SpdLogger->set_level(spdlog::level::info);
303                     GmmLoggerPerProc.SpdLogger->info(temp);
304                     break;
305                 case Error:
306                     GmmLoggerPerProc.SpdLogger->critical(temp);
307                     break;
308                 default:
309                     break;
310             }
311 
312             delete[] temp;
313         }
314     }
315 
316     va_end(args);
317 }
318 
319 #endif //#if GMM_LOG_AVAILABLE
320