xref: /aosp_15_r20/external/openscreen/tools/cddl/logging.h (revision 3f982cf4871df8771c9d4abe6e9a6f8d829b2736)
1*3f982cf4SFabien Sanglard // Copyright 2019 The Chromium Authors. All rights reserved.
2*3f982cf4SFabien Sanglard // Use of this source code is governed by a BSD-style license that can be
3*3f982cf4SFabien Sanglard // found in the LICENSE file.
4*3f982cf4SFabien Sanglard 
5*3f982cf4SFabien Sanglard #ifndef TOOLS_CDDL_LOGGING_H_
6*3f982cf4SFabien Sanglard #define TOOLS_CDDL_LOGGING_H_
7*3f982cf4SFabien Sanglard 
8*3f982cf4SFabien Sanglard #include <stdio.h>
9*3f982cf4SFabien Sanglard #include <stdlib.h>
10*3f982cf4SFabien Sanglard 
11*3f982cf4SFabien Sanglard #include <cstdlib>
12*3f982cf4SFabien Sanglard #include <iostream>
13*3f982cf4SFabien Sanglard #include <string>
14*3f982cf4SFabien Sanglard #include <utility>
15*3f982cf4SFabien Sanglard 
16*3f982cf4SFabien Sanglard #define CHECK(condition) (condition) ? (void)0 : Logger::Abort(#condition)
17*3f982cf4SFabien Sanglard 
18*3f982cf4SFabien Sanglard #define CHECK_EQ(a, b) CHECK((a) == (b))
19*3f982cf4SFabien Sanglard #define CHECK_NE(a, b) CHECK((a) != (b))
20*3f982cf4SFabien Sanglard #define CHECK_LT(a, b) CHECK((a) < (b))
21*3f982cf4SFabien Sanglard #define CHECK_LE(a, b) CHECK((a) <= (b))
22*3f982cf4SFabien Sanglard #define CHECK_GT(a, b) CHECK((a) > (b))
23*3f982cf4SFabien Sanglard #define CHECK_GE(a, b) CHECK((a) >= (b))
24*3f982cf4SFabien Sanglard 
25*3f982cf4SFabien Sanglard // TODO(crbug.com/openscreen/75):
26*3f982cf4SFabien Sanglard // #1: This class has no state, so it doesn't need to be a singleton, just
27*3f982cf4SFabien Sanglard // a collection of static functions.
28*3f982cf4SFabien Sanglard //
29*3f982cf4SFabien Sanglard // #2: Convert to stream oriented logging to clean up security warnings.
30*3f982cf4SFabien Sanglard class Logger {
31*3f982cf4SFabien Sanglard  public:
32*3f982cf4SFabien Sanglard   // Writes a log to the global singleton instance of Logger.
33*3f982cf4SFabien Sanglard   template <typename... Args>
Log(const std::string & message,Args &&...args)34*3f982cf4SFabien Sanglard   static void Log(const std::string& message, Args&&... args) {
35*3f982cf4SFabien Sanglard     Logger::Get()->WriteLog(message, std::forward<Args>(args)...);
36*3f982cf4SFabien Sanglard   }
37*3f982cf4SFabien Sanglard 
38*3f982cf4SFabien Sanglard   // Writes an error to the global singleton instance of Logger.
39*3f982cf4SFabien Sanglard   template <typename... Args>
Error(const std::string & message,Args &&...args)40*3f982cf4SFabien Sanglard   static void Error(const std::string& message, Args&&... args) {
41*3f982cf4SFabien Sanglard     Logger::Get()->WriteError(message, std::forward<Args>(args)...);
42*3f982cf4SFabien Sanglard   }
43*3f982cf4SFabien Sanglard 
44*3f982cf4SFabien Sanglard   // Returns the singleton instance of Logger.
45*3f982cf4SFabien Sanglard   static Logger* Get();
46*3f982cf4SFabien Sanglard 
47*3f982cf4SFabien Sanglard   // Aborts the program after logging the condition that caused the
48*3f982cf4SFabien Sanglard   // CHECK-failure.
49*3f982cf4SFabien Sanglard   static void Abort(const char* condition);
50*3f982cf4SFabien Sanglard 
51*3f982cf4SFabien Sanglard  private:
52*3f982cf4SFabien Sanglard   // Creates and initializes the logging file associated with this logger.
53*3f982cf4SFabien Sanglard   void InitializeInstance();
54*3f982cf4SFabien Sanglard 
55*3f982cf4SFabien Sanglard   // Limit calling the constructor/destructor to from within this same class.
56*3f982cf4SFabien Sanglard   Logger();
57*3f982cf4SFabien Sanglard 
58*3f982cf4SFabien Sanglard   // Represents whether this instance has been initialized.
59*3f982cf4SFabien Sanglard   bool is_initialized_;
60*3f982cf4SFabien Sanglard 
61*3f982cf4SFabien Sanglard   // Singleton instance of logger. At the beginning of runtime it's initiated to
62*3f982cf4SFabien Sanglard   // nullptr due to zero initialization.
63*3f982cf4SFabien Sanglard   static Logger* singleton_;
64*3f982cf4SFabien Sanglard 
65*3f982cf4SFabien Sanglard   // Exits the program if initialization has not occured.
66*3f982cf4SFabien Sanglard   void VerifyInitialized();
67*3f982cf4SFabien Sanglard 
68*3f982cf4SFabien Sanglard   // fprintf doesn't like passing strings as parameters, so use overloads to
69*3f982cf4SFabien Sanglard   // convert all C++ std::string types into C strings.
70*3f982cf4SFabien Sanglard   template <class T>
MakePrintable(const T data)71*3f982cf4SFabien Sanglard   T MakePrintable(const T data) {
72*3f982cf4SFabien Sanglard     return data;
73*3f982cf4SFabien Sanglard   }
74*3f982cf4SFabien Sanglard 
75*3f982cf4SFabien Sanglard   const char* MakePrintable(const std::string& data);
76*3f982cf4SFabien Sanglard 
77*3f982cf4SFabien Sanglard   // Writes a log message to this instance of Logger's text file.
78*3f982cf4SFabien Sanglard   template <typename... Args>
WriteToStream(const std::string & message,Args &&...args)79*3f982cf4SFabien Sanglard   void WriteToStream(const std::string& message, Args&&... args) {
80*3f982cf4SFabien Sanglard     VerifyInitialized();
81*3f982cf4SFabien Sanglard 
82*3f982cf4SFabien Sanglard     // NOTE: wihout the #pragma suppressions, the below line fails. There is a
83*3f982cf4SFabien Sanglard     // warning generated since the compiler is attempting to prevent a string
84*3f982cf4SFabien Sanglard     // format vulnerability. This is not a risk for us since this code is only
85*3f982cf4SFabien Sanglard     // used at compile time. The below #pragma commands suppress the warning for
86*3f982cf4SFabien Sanglard     // just the one dprintf(...) line.
87*3f982cf4SFabien Sanglard     // For more details: https://www.owasp.org/index.php/Format_string_attack
88*3f982cf4SFabien Sanglard     char* str_buffer;
89*3f982cf4SFabien Sanglard #if defined(__clang__)
90*3f982cf4SFabien Sanglard #pragma clang diagnostic push
91*3f982cf4SFabien Sanglard #pragma clang diagnostic ignored "-Wformat-security"
92*3f982cf4SFabien Sanglard #elif defined(__GNUC__)
93*3f982cf4SFabien Sanglard #pragma GCC diagnostic push
94*3f982cf4SFabien Sanglard #pragma GCC diagnostic ignored "-Wformat-security"
95*3f982cf4SFabien Sanglard #endif  // defined(__clang__)
96*3f982cf4SFabien Sanglard     int byte_count = asprintf(&str_buffer, message.c_str(),
97*3f982cf4SFabien Sanglard                               this->MakePrintable(std::forward<Args>(args))...);
98*3f982cf4SFabien Sanglard #if defined(__clang__)
99*3f982cf4SFabien Sanglard #pragma clang diagnostic pop
100*3f982cf4SFabien Sanglard #elif defined(__GNUC__)
101*3f982cf4SFabien Sanglard #pragma GCC diagnostic pop
102*3f982cf4SFabien Sanglard #endif  // defined(__clang__)
103*3f982cf4SFabien Sanglard     CHECK_GE(byte_count, 0);
104*3f982cf4SFabien Sanglard     std::cerr << str_buffer << std::endl;
105*3f982cf4SFabien Sanglard     free(str_buffer);
106*3f982cf4SFabien Sanglard   }
107*3f982cf4SFabien Sanglard 
108*3f982cf4SFabien Sanglard   // Writes an error message.
109*3f982cf4SFabien Sanglard   template <typename... Args>
WriteError(const std::string & message,Args &&...args)110*3f982cf4SFabien Sanglard   void WriteError(const std::string& message, Args&&... args) {
111*3f982cf4SFabien Sanglard     WriteToStream("Error: " + message, std::forward<Args>(args)...);
112*3f982cf4SFabien Sanglard   }
113*3f982cf4SFabien Sanglard 
114*3f982cf4SFabien Sanglard   // Writes a log message.
115*3f982cf4SFabien Sanglard   template <typename... Args>
WriteLog(const std::string & message,Args &&...args)116*3f982cf4SFabien Sanglard   void WriteLog(const std::string& message, Args&&... args) {
117*3f982cf4SFabien Sanglard     WriteToStream(message, std::forward<Args>(args)...);
118*3f982cf4SFabien Sanglard   }
119*3f982cf4SFabien Sanglard };
120*3f982cf4SFabien Sanglard 
121*3f982cf4SFabien Sanglard #endif  // TOOLS_CDDL_LOGGING_H_
122