Google Cloud C++ Client  0.4.0
C++ Client Library for Google Cloud Platform
log.cc
Go to the documentation of this file.
1 // Copyright 2018 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "google/cloud/log.h"
16 
17 namespace google {
18 namespace cloud {
19 inline namespace GOOGLE_CLOUD_CPP_NS {
20 static_assert(sizeof(Severity) <= sizeof(int),
21  "Expected Severity to fit in an integer");
22 
23 static_assert(static_cast<int>(Severity::GCP_LS_LOWEST) <
24  static_cast<int>(Severity::GCP_LS_HIGHEST),
25  "Expect LOWEST severity to be smaller than HIGHEST severity");
26 
27 std::ostream& operator<<(std::ostream& os, Severity x) {
28  char const* names[] = {
29  "TRACE", "DEBUG", "INFO", "NOTICE", "WARNING",
30  "ERROR", "CRITICAL", "ALERT", "FATAL",
31  };
32  auto index = static_cast<int>(x);
33  return os << names[index];
34 }
35 
36 std::ostream& operator<<(std::ostream& os, LogRecord const& rhs) {
37  return os << '[' << rhs.severity << "] " << rhs.message << " ("
38  << rhs.filename << ':' << rhs.lineno << ')';
39 }
40 
42  : empty_(true),
43  minimum_severity_(static_cast<int>(Severity::GCP_LS_LOWEST_ENABLED)),
44  next_id_(0),
45  clog_backend_id_(0) {}
46 
48  static LogSink instance;
49  return instance;
50 }
51 
52 long LogSink::AddBackend(std::shared_ptr<LogBackend> backend) {
53  std::unique_lock<std::mutex> lk(mu_);
54  return AddBackendImpl(std::move(backend));
55 }
56 
57 void LogSink::RemoveBackend(long id) {
58  std::unique_lock<std::mutex> lk(mu_);
59  RemoveBackendImpl(id);
60 }
61 
63  std::unique_lock<std::mutex> lk(mu_);
64  backends_.clear();
65  clog_backend_id_ = 0;
66  empty_.store(backends_.empty());
67 }
68 
69 std::size_t LogSink::BackendCount() const {
70  std::unique_lock<std::mutex> lk(mu_);
71  return backends_.size();
72 }
73 
74 void LogSink::Log(LogRecord log_record) {
75  // Make a copy of the backends because calling user-defined functions while
76  // holding a lock is a bad idea: the application may change the backends while
77  // we are holding this lock, and soon deadlock occurs.
78  auto copy = [this]() {
79  std::unique_lock<std::mutex> lk(mu_);
80  return backends_;
81  }();
82  if (copy.empty()) {
83  return;
84  }
85  // In general, we just give each backend a const-reference and the backends
86  // must make a copy if needed. But if there is only one backend we can give
87  // the backend an opportunity to optimize things by transferring ownership of
88  // the LogRecord to it.
89  if (1U == copy.size()) {
90  copy.begin()->second->ProcessWithOwnership(std::move(log_record));
91  return;
92  }
93  for (auto& kv : copy) {
94  kv.second->Process(log_record);
95  }
96 }
97 
98 namespace {
99 class StdClogBackend : public LogBackend {
100  public:
101  StdClogBackend() = default;
102 
103  void Process(LogRecord const& lr) override {
104  std::clog << lr << "\n";
106  std::clog << std::flush;
107  }
108  }
109  void ProcessWithOwnership(LogRecord lr) override { Process(lr); }
110 };
111 } // namespace
112 
113 void LogSink::EnableStdClogImpl() {
114  std::unique_lock<std::mutex> lk(mu_);
115  if (clog_backend_id_ != 0) {
116  return;
117  }
118  clog_backend_id_ = AddBackendImpl(std::make_shared<StdClogBackend>());
119 }
120 
121 void LogSink::DisableStdClogImpl() {
122  std::unique_lock<std::mutex> lk(mu_);
123  if (clog_backend_id_ == 0) {
124  return;
125  }
126  RemoveBackendImpl(clog_backend_id_);
127  clog_backend_id_ = 0;
128 }
129 
130 long LogSink::AddBackendImpl(std::shared_ptr<LogBackend> backend) {
131  long id = ++next_id_;
132  backends_.emplace(id, std::move(backend));
133  empty_.store(backends_.empty());
134  return id;
135 }
136 
137 void LogSink::RemoveBackendImpl(long id) {
138  auto it = backends_.find(id);
139  if (backends_.end() == it) {
140  return;
141  }
142  backends_.erase(it);
143  empty_.store(backends_.empty());
144 }
145 
146 } // namespace GOOGLE_CLOUD_CPP_NS
147 } // namespace cloud
148 } // namespace google
A sink to receive log records.
Definition: log.h:222
#define GOOGLE_CLOUD_CPP_NS
Definition: version.h:24
Contains all the Google Cloud C++ Library APIs.
Definition: iam_bindings.cc:21
long AddBackend(std::shared_ptr< LogBackend > backend)
Definition: log.cc:52
void Log(LogRecord log_record)
Definition: log.cc:74
std::string filename
Definition: log.h:210
The highest possible severity level.
The lowest possible severity level.
std::string message
Definition: log.h:213
virtual void ProcessWithOwnership(LogRecord log_record)=0
void RemoveBackend(long id)
Definition: log.cc:57
Severity
Define the severity levels for Google Cloud Platform C++ Libraries logging.
Definition: log.h:171
Represents a single log message.
Definition: log.h:207
static LogSink & Instance()
Return the singleton instance for this application.
Definition: log.cc:47
std::size_t BackendCount() const
Definition: log.cc:69
The lowest level that is enabled at compile-time.
An indication of problems, users may need to take action.
virtual void Process(LogRecord const &log_record)=0