aboutsummaryrefslogtreecommitdiff
path: root/icing/util/logging.h
blob: 77423029bfa09bc429b6db528a1c783b917d9297 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// Copyright (C) 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef ICING_UTIL_LOGGING_H_
#define ICING_UTIL_LOGGING_H_

#include <atomic>
#include <cstdint>
#include <string>

#include "icing/proto/debug.pb.h"

// This header provides base/logging.h style macros, ICING_LOG and ICING_VLOG,
// for logging in various platforms. The macros use __android_log_write on
// Android, and log to stdout/stderr on others. It also provides a function
// SetLoggingLevel to control the log severity level for ICING_LOG and verbosity
// for ICING_VLOG.
namespace icing {
namespace lib {

// Whether we should log according to the current logging level.
// The function will always return false when verbosity is negative.
bool ShouldLog(LogSeverity::Code severity, int16_t verbosity = 0);

// Set the minimal logging severity to be enabled, and the verbose level to see
// from the logs.
// Return false if severity is set higher than VERBOSE but verbosity is not 0.
// The function will always return false when verbosity is negative.
bool SetLoggingLevel(LogSeverity::Code severity, int16_t verbosity = 0);

// A tiny code footprint string stream for assembling log messages.
struct LoggingStringStream {
  explicit LoggingStringStream(bool should_log) : should_log_(should_log) {}
  LoggingStringStream& stream() { return *this; }

  std::string message;
  const bool should_log_;
};

template <typename T>
inline LoggingStringStream& operator<<(LoggingStringStream& stream,
                                       const T& entry) {
  if (stream.should_log_) {
    stream.message.append(std::to_string(entry));
  }
  return stream;
}

template <typename T>
inline LoggingStringStream& operator<<(LoggingStringStream& stream,
                                       T* const entry) {
  if (stream.should_log_) {
    stream.message.append(
        std::to_string(reinterpret_cast<const uint64_t>(entry)));
  }
  return stream;
}

inline LoggingStringStream& operator<<(LoggingStringStream& stream,
                                       const char* message) {
  if (stream.should_log_) {
    stream.message.append(message);
  }
  return stream;
}

inline LoggingStringStream& operator<<(LoggingStringStream& stream,
                                       const std::string& message) {
  if (stream.should_log_) {
    stream.message.append(message);
  }
  return stream;
}

inline LoggingStringStream& operator<<(LoggingStringStream& stream,
                                       std::string_view message) {
  if (stream.should_log_) {
    stream.message.append(message);
  }
  return stream;
}

template <typename T1, typename T2>
inline LoggingStringStream& operator<<(LoggingStringStream& stream,
                                       const std::pair<T1, T2>& entry) {
  if (stream.should_log_) {
    stream << "(" << entry.first << ", " << entry.second << ")";
  }
  return stream;
}

// The class that does all the work behind our ICING_LOG(severity) macros.  Each
// ICING_LOG(severity) << obj1 << obj2 << ...; logging statement creates a
// LogMessage temporary object containing a stringstream.  Each operator<< adds
// info to that stringstream and the LogMessage destructor performs the actual
// logging.  The reason this works is that in C++, "all temporary objects are
// destroyed as the last step in evaluating the full-expression that (lexically)
// contains the point where they were created."  For more info, see
// http://en.cppreference.com/w/cpp/language/lifetime.  Hence, the destructor is
// invoked after the last << from that logging statement.
class LogMessage {
 public:
  LogMessage(LogSeverity::Code severity, uint16_t verbosity,
             const char* file_name, int line_number) __attribute__((noinline));

  ~LogMessage() __attribute__((noinline));

  // Returns the stream associated with the logger object.
  LoggingStringStream& stream() { return stream_; }

 private:
  const LogSeverity::Code severity_;
  const uint16_t verbosity_;
  const bool should_log_;

  // Stream that "prints" all info into a string (not to a file).  We construct
  // here the entire logging message and next print it in one operation.
  LoggingStringStream stream_;
};

inline constexpr char kIcingLoggingTag[] = "AppSearchIcing";

#define ICING_VLOG(verbose_level)                                             \
  ::icing::lib::LogMessage(::icing::lib::LogSeverity::VERBOSE, verbose_level, \
                           __FILE__, __LINE__)                                \
      .stream()
#define ICING_LOG(severity)                                     \
  ::icing::lib::LogMessage(::icing::lib::LogSeverity::severity, \
                           /*verbosity=*/0, __FILE__, __LINE__) \
      .stream()

}  // namespace lib
}  // namespace icing

#endif  // ICING_UTIL_LOGGING_H_