Coverage Report

Created: 2023-09-25 06:27

/src/abseil-cpp/absl/log/internal/log_sink_set.cc
Line
Count
Source (jump to first uncovered line)
1
//
2
// Copyright 2022 The Abseil Authors.
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
//      https://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
#include "absl/log/internal/log_sink_set.h"
17
18
#ifndef ABSL_HAVE_THREAD_LOCAL
19
#include <pthread.h>
20
#endif
21
22
#ifdef __ANDROID__
23
#include <android/log.h>
24
#endif
25
26
#ifdef _WIN32
27
#include <windows.h>
28
#endif
29
30
#include <algorithm>
31
#include <vector>
32
33
#include "absl/base/attributes.h"
34
#include "absl/base/call_once.h"
35
#include "absl/base/config.h"
36
#include "absl/base/internal/raw_logging.h"
37
#include "absl/base/log_severity.h"
38
#include "absl/base/thread_annotations.h"
39
#include "absl/cleanup/cleanup.h"
40
#include "absl/log/globals.h"
41
#include "absl/log/internal/config.h"
42
#include "absl/log/internal/globals.h"
43
#include "absl/log/log_entry.h"
44
#include "absl/log/log_sink.h"
45
#include "absl/strings/string_view.h"
46
#include "absl/synchronization/mutex.h"
47
#include "absl/types/span.h"
48
49
namespace absl {
50
ABSL_NAMESPACE_BEGIN
51
namespace log_internal {
52
namespace {
53
54
// Returns a mutable reference to a thread-local variable that should be true if
55
// a globally-registered `LogSink`'s `Send()` is currently being invoked on this
56
// thread.
57
12.9M
bool& ThreadIsLoggingStatus() {
58
12.9M
#ifdef ABSL_HAVE_THREAD_LOCAL
59
12.9M
  ABSL_CONST_INIT thread_local bool thread_is_logging = false;
60
12.9M
  return thread_is_logging;
61
#else
62
  ABSL_CONST_INIT static pthread_key_t thread_is_logging_key;
63
  static const bool unused = [] {
64
    if (pthread_key_create(&thread_is_logging_key, [](void* data) {
65
          delete reinterpret_cast<bool*>(data);
66
        })) {
67
      perror("pthread_key_create failed!");
68
      abort();
69
    }
70
    return true;
71
  }();
72
  (void)unused;  // Fixes -wunused-variable warning
73
  bool* thread_is_logging_ptr =
74
      reinterpret_cast<bool*>(pthread_getspecific(thread_is_logging_key));
75
76
  if (ABSL_PREDICT_FALSE(!thread_is_logging_ptr)) {
77
    thread_is_logging_ptr = new bool{false};
78
    if (pthread_setspecific(thread_is_logging_key, thread_is_logging_ptr)) {
79
      perror("pthread_setspecific failed");
80
      abort();
81
    }
82
  }
83
  return *thread_is_logging_ptr;
84
#endif
85
12.9M
}
86
87
class StderrLogSink final : public LogSink {
88
 public:
89
  ~StderrLogSink() override = default;
90
91
3.24M
  void Send(const absl::LogEntry& entry) override {
92
3.24M
    if (entry.log_severity() < absl::StderrThreshold() &&
93
3.24M
        absl::log_internal::IsInitialized()) {
94
0
      return;
95
0
    }
96
97
3.24M
    ABSL_CONST_INIT static absl::once_flag warn_if_not_initialized;
98
3.24M
    absl::call_once(warn_if_not_initialized, []() {
99
1
      if (absl::log_internal::IsInitialized()) return;
100
1
      const char w[] =
101
1
          "WARNING: All log messages before absl::InitializeLog() is called"
102
1
          " are written to STDERR\n";
103
1
      absl::log_internal::WriteToStderr(w, absl::LogSeverity::kWarning);
104
1
    });
105
106
3.24M
    if (!entry.stacktrace().empty()) {
107
0
      absl::log_internal::WriteToStderr(entry.stacktrace(),
108
0
                                        entry.log_severity());
109
3.24M
    } else {
110
      // TODO(b/226937039): do this outside else condition once we avoid
111
      // ReprintFatalMessage
112
3.24M
      absl::log_internal::WriteToStderr(
113
3.24M
          entry.text_message_with_prefix_and_newline(), entry.log_severity());
114
3.24M
    }
115
3.24M
  }
116
};
117
118
#if defined(__ANDROID__)
119
class AndroidLogSink final : public LogSink {
120
 public:
121
  ~AndroidLogSink() override = default;
122
123
  void Send(const absl::LogEntry& entry) override {
124
    const int level = AndroidLogLevel(entry);
125
    const char* const tag = GetAndroidNativeTag();
126
    __android_log_write(level, tag,
127
                        entry.text_message_with_prefix_and_newline_c_str());
128
    if (entry.log_severity() == absl::LogSeverity::kFatal)
129
      __android_log_write(ANDROID_LOG_FATAL, tag, "terminating.\n");
130
  }
131
132
 private:
133
  static int AndroidLogLevel(const absl::LogEntry& entry) {
134
    switch (entry.log_severity()) {
135
      case absl::LogSeverity::kFatal:
136
        return ANDROID_LOG_FATAL;
137
      case absl::LogSeverity::kError:
138
        return ANDROID_LOG_ERROR;
139
      case absl::LogSeverity::kWarning:
140
        return ANDROID_LOG_WARN;
141
      default:
142
        if (entry.verbosity() >= 2) return ANDROID_LOG_VERBOSE;
143
        if (entry.verbosity() == 1) return ANDROID_LOG_DEBUG;
144
        return ANDROID_LOG_INFO;
145
    }
146
  }
147
};
148
#endif  // !defined(__ANDROID__)
149
150
#if defined(_WIN32)
151
class WindowsDebuggerLogSink final : public LogSink {
152
 public:
153
  ~WindowsDebuggerLogSink() override = default;
154
155
  void Send(const absl::LogEntry& entry) override {
156
    if (entry.log_severity() < absl::StderrThreshold() &&
157
        absl::log_internal::IsInitialized()) {
158
      return;
159
    }
160
    ::OutputDebugStringA(entry.text_message_with_prefix_and_newline_c_str());
161
  }
162
};
163
#endif  // !defined(_WIN32)
164
165
class GlobalLogSinkSet final {
166
 public:
167
1
  GlobalLogSinkSet() {
168
#if defined(__myriad2__) || defined(__Fuchsia__)
169
    // myriad2 and Fuchsia do not log to stderr by default.
170
#else
171
1
    static StderrLogSink* stderr_log_sink = new StderrLogSink;
172
1
    AddLogSink(stderr_log_sink);
173
1
#endif
174
#ifdef __ANDROID__
175
    static AndroidLogSink* android_log_sink = new AndroidLogSink;
176
    AddLogSink(android_log_sink);
177
#endif
178
#if defined(_WIN32)
179
    static WindowsDebuggerLogSink* debugger_log_sink =
180
        new WindowsDebuggerLogSink;
181
    AddLogSink(debugger_log_sink);
182
#endif  // !defined(_WIN32)
183
1
  }
184
185
  void LogToSinks(const absl::LogEntry& entry,
186
                  absl::Span<absl::LogSink*> extra_sinks, bool extra_sinks_only)
187
3.24M
      ABSL_LOCKS_EXCLUDED(guard_) {
188
3.24M
    SendToSinks(entry, extra_sinks);
189
190
3.24M
    if (!extra_sinks_only) {
191
3.24M
      if (ThreadIsLoggingToLogSink()) {
192
0
        absl::log_internal::WriteToStderr(
193
0
            entry.text_message_with_prefix_and_newline(), entry.log_severity());
194
3.24M
      } else {
195
3.24M
        absl::ReaderMutexLock global_sinks_lock(&guard_);
196
3.24M
        ThreadIsLoggingStatus() = true;
197
        // Ensure the "thread is logging" status is reverted upon leaving the
198
        // scope even in case of exceptions.
199
3.24M
        auto status_cleanup =
200
3.24M
            absl::MakeCleanup([] { ThreadIsLoggingStatus() = false; });
201
3.24M
        SendToSinks(entry, absl::MakeSpan(sinks_));
202
3.24M
      }
203
3.24M
    }
204
3.24M
  }
205
206
1
  void AddLogSink(absl::LogSink* sink) ABSL_LOCKS_EXCLUDED(guard_) {
207
1
    {
208
1
      absl::WriterMutexLock global_sinks_lock(&guard_);
209
1
      auto pos = std::find(sinks_.begin(), sinks_.end(), sink);
210
1
      if (pos == sinks_.end()) {
211
1
        sinks_.push_back(sink);
212
1
        return;
213
1
      }
214
1
    }
215
0
    ABSL_INTERNAL_LOG(FATAL, "Duplicate log sinks are not supported");
216
0
  }
217
218
0
  void RemoveLogSink(absl::LogSink* sink) ABSL_LOCKS_EXCLUDED(guard_) {
219
0
    {
220
0
      absl::WriterMutexLock global_sinks_lock(&guard_);
221
0
      auto pos = std::find(sinks_.begin(), sinks_.end(), sink);
222
0
      if (pos != sinks_.end()) {
223
0
        sinks_.erase(pos);
224
0
        return;
225
0
      }
226
0
    }
227
0
    ABSL_INTERNAL_LOG(FATAL, "Mismatched log sink being removed");
228
0
  }
229
230
0
  void FlushLogSinks() ABSL_LOCKS_EXCLUDED(guard_) {
231
0
    if (ThreadIsLoggingToLogSink()) {
232
      // The thread_local condition demonstrates that we're already holding the
233
      // lock in order to iterate over `sinks_` for dispatch.  The thread-safety
234
      // annotations don't know this, so we use `ABSL_NO_THREAD_SAFETY_ANALYSIS`
235
0
      guard_.AssertReaderHeld();
236
0
      FlushLogSinksLocked();
237
0
    } else {
238
0
      absl::ReaderMutexLock global_sinks_lock(&guard_);
239
      // In case if LogSink::Flush overload decides to log
240
0
      ThreadIsLoggingStatus() = true;
241
      // Ensure the "thread is logging" status is reverted upon leaving the
242
      // scope even in case of exceptions.
243
0
      auto status_cleanup =
244
0
          absl::MakeCleanup([] { ThreadIsLoggingStatus() = false; });
245
0
      FlushLogSinksLocked();
246
0
    }
247
0
  }
248
249
 private:
250
0
  void FlushLogSinksLocked() ABSL_SHARED_LOCKS_REQUIRED(guard_) {
251
0
    for (absl::LogSink* sink : sinks_) {
252
0
      sink->Flush();
253
0
    }
254
0
  }
255
256
  // Helper routine for LogToSinks.
257
  static void SendToSinks(const absl::LogEntry& entry,
258
6.48M
                          absl::Span<absl::LogSink*> sinks) {
259
6.48M
    for (absl::LogSink* sink : sinks) {
260
3.24M
      sink->Send(entry);
261
3.24M
    }
262
6.48M
  }
263
264
  using LogSinksSet = std::vector<absl::LogSink*>;
265
  absl::Mutex guard_;
266
  LogSinksSet sinks_ ABSL_GUARDED_BY(guard_);
267
};
268
269
// Returns reference to the global LogSinks set.
270
3.24M
GlobalLogSinkSet& GlobalSinks() {
271
3.24M
  static GlobalLogSinkSet* global_sinks = new GlobalLogSinkSet;
272
3.24M
  return *global_sinks;
273
3.24M
}
274
275
}  // namespace
276
277
6.48M
bool ThreadIsLoggingToLogSink() { return ThreadIsLoggingStatus(); }
278
279
void LogToSinks(const absl::LogEntry& entry,
280
3.24M
                absl::Span<absl::LogSink*> extra_sinks, bool extra_sinks_only) {
281
3.24M
  log_internal::GlobalSinks().LogToSinks(entry, extra_sinks, extra_sinks_only);
282
3.24M
}
283
284
0
void AddLogSink(absl::LogSink* sink) {
285
0
  log_internal::GlobalSinks().AddLogSink(sink);
286
0
}
287
288
0
void RemoveLogSink(absl::LogSink* sink) {
289
0
  log_internal::GlobalSinks().RemoveLogSink(sink);
290
0
}
291
292
0
void FlushLogSinks() { log_internal::GlobalSinks().FlushLogSinks(); }
293
294
}  // namespace log_internal
295
ABSL_NAMESPACE_END
296
}  // namespace absl