kmsp11/util/logging.cc (126 lines of code) (raw):

// Copyright 2021 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. #include "kmsp11/util/logging.h" #include "absl/base/log_severity.h" #include "absl/log/initialize.h" #include "absl/log/log_sink.h" #include "absl/log/log_sink_registry.h" #include "absl/synchronization/mutex.h" #include "common/platform.h" #include "common/status_utils.h" #include "glog/logging.h" #include "grpc/support/log.h" #include "kmsp11/util/errors.h" #include "kmsp11/util/status_utils.h" namespace cloud_kms::kmsp11 { namespace { ABSL_CONST_INIT static absl::Mutex logging_lock(absl::kConstInit); static bool logging_initialized ABSL_GUARDED_BY(logging_lock); void GrpcLog(gpr_log_func_args* args) { // Map gRPC severities to glog severities. // gRPC severities: ERROR, INFO, DEBUG // glog severities: FATAL, ERROR, WARNING, INFO google::LogSeverity severity; switch (args->severity) { // gRPC ERROR -> glog WARNING. gRPC errors aren't necessarily errors for // us; see e.g. https://github.com/grpc/grpc/issues/22613. We should emit // our own message at level ERROR for events that we consider errors. case GPR_LOG_SEVERITY_ERROR: severity = google::GLOG_WARNING; break; // gRPC INFO and gRPC DEBUG -> glog INFO. Note that, by default, gRPC will // not pass us messages at these levels. The GRPC_VERBOSITY environment // variable would need to be set. // https://github.com/grpc/grpc/blob/master/TROUBLESHOOTING.md#grpc_verbosity default: severity = google::GLOG_INFO; break; } google::LogMessage(args->file, args->line, severity).stream() << args->message; } // A sink to translate Abseil log messages into Glog log messages. class GlogSink : public absl::LogSink { public: virtual void Send(const absl::LogEntry& entry) override { google::LogSeverity severity; switch (entry.log_severity()) { case absl::LogSeverity::kError: severity = google::GLOG_ERROR; break; case absl::LogSeverity::kWarning: severity = google::GLOG_WARNING; break; default: severity = google::GLOG_INFO; break; } google::LogMessage(entry.source_filename().data(), entry.source_line(), severity) .stream() << entry.text_message(); } }; // Redirection from gRPC and Abseil logs to Glog should happen once in the // lifetime of the program. static const bool kOneTimeInitialized = [] { gpr_set_log_function(&GrpcLog); absl::AddLogSink(new GlogSink()); // "leak" OK - we need this sink for the // duration of the program. absl::InitializeLog(); return true; }(); } // namespace absl::Status InitializeLogging(std::string_view output_directory, std::string_view output_filename_suffix) { absl::WriterMutexLock lock(&logging_lock); if (logging_initialized) { return NewInternalError("logging is already initialized", SOURCE_LOCATION); } if (output_directory.empty()) { google::SetStderrLogging(google::GLOG_INFO); // Disable discrete log files for all levels. for (google::LogSeverity severity : {google::GLOG_INFO, google::GLOG_WARNING, google::GLOG_ERROR, google::GLOG_FATAL}) { google::SetLogDestination(severity, ""); google::SetLogSymlink(severity, ""); } } else { // FATAL logs crash the program; emit these to standard error as well. google::SetStderrLogging(google::GLOG_FATAL); if (!output_filename_suffix.empty()) { google::SetLogDestination( google::GLOG_INFO, absl::StrCat(output_directory, "/libkmsp11.log-", output_filename_suffix, "-") .c_str()); } else { google::SetLogDestination( google::GLOG_INFO, absl::StrCat(output_directory, "/libkmsp11.log-").c_str()); } // Disable symlink creation, which causes removal issues on FreeBSD. // https://www.mail-archive.com/freebsd-bugs@freebsd.org/msg79713.html google::SetLogSymlink(google::GLOG_INFO, ""); // Disable discrete log files for all levels but INFO -- they all still // get logged to the INFO logfile. for (google::LogSeverity severity : {google::GLOG_WARNING, google::GLOG_ERROR, google::GLOG_FATAL}) { google::SetLogDestination(severity, ""); google::SetLogSymlink(severity, ""); } } google::InitGoogleLogging("libkmsp11"); logging_initialized = true; return absl::OkStatus(); } void ShutdownLogging() { absl::WriterMutexLock lock(&logging_lock); if (logging_initialized) { google::ShutdownGoogleLogging(); logging_initialized = false; } } CK_RV LogAndResolve(std::string_view function_name, const absl::Status& status) { if (status.ok()) { return CKR_OK; } CK_RV rv = GetCkRv(status); std::string message = absl::StrFormat("returning %#x from %s due to status %s", rv, function_name, status.ToString()); absl::ReaderMutexLock lock(&logging_lock); if (!logging_initialized) { // This failure occurred before library initialization. Write output to // standard error and to the syslog (on Posix) so that it lands /somewhere/. std::string preout_message = absl::StrCat( "kmsp11 failure occurred prior to library initialization: ", message); std::cerr << preout_message << std::endl; WriteToSystemLog(preout_message.c_str()); return rv; } if (absl::IsInternal(status)) { // Internal statuses mean some library assumption was violated, so treat // this more severely than a business error. LOG(ERROR) << message; return rv; } // Treat all other non-OK statuses as business errors. LOG(INFO) << message; return rv; } } // namespace cloud_kms::kmsp11