blob: 7768978645963055e5eb79d6eff31bc5d93ef2f8 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "sdk/lib/syslog/cpp/logging_backend_fuchsia_globals.h"
#include "sdk/lib/syslog/structured_backend/cpp/log_connection.h"
#include "sdk/lib/syslog/structured_backend/cpp/logger.h"
#include "sdk/lib/syslog/structured_backend/cpp/raw_log_settings.h"
#include "sdk/lib/syslog/structured_backend/fuchsia_syslog.h"
#ifndef _ALL_SOURCE
#define _ALL_SOURCE // To get MTX_INIT
#endif
#include <lib/zx/result.h>
#include <zircon/assert.h>
#include <zircon/compiler.h>
#include <zircon/process.h>
#include <zircon/syscalls.h>
#include <condition_variable>
#include <mutex>
namespace fuchsia_logging::internal {
class LogState;
namespace {
LogState* state = nullptr;
std::mutex state_lock;
// This thread's koid.
// Initialized on first use.
thread_local zx_koid_t tls_thread_koid{ZX_KOID_INVALID};
zx_koid_t GetKoid(zx_handle_t handle) {
zx_info_handle_basic_t info;
zx_status_t status =
zx_object_get_info(handle, ZX_INFO_HANDLE_BASIC, &info, sizeof(info), nullptr, nullptr);
return status == ZX_OK ? info.koid : ZX_KOID_INVALID;
}
} // namespace
#if FUCHSIA_API_LEVEL_AT_LEAST(NEXT)
// This is internal::Logger which is distinct from the public one. This is currently only used for
// the global logger.
class Logger {
public:
static void InitGlobalInstance(const RawLogSettings& settings) {
bool called = false;
std::call_once(once_, [&called, settings]() {
called = true;
if (auto logger = fuchsia_logging::Logger::Create(settings, &min_severity_); logger.is_ok()) {
global_instance_ = new Logger(*std::move(logger));
} else {
global_instance_ = new Logger;
}
});
if (!called) {
auto logger = fuchsia_logging::Logger::Create(settings, &min_severity_);
std::scoped_lock lock(global_instance_->mutex_);
if (logger.is_ok()) {
global_instance_->logger_ = *std::move(logger);
} else {
global_instance_->logger_ = {};
}
}
}
static Logger& GlobalInstance(RawLogSettings (*get_default_settings)()) {
std::call_once(once_, [get_default_settings] {
if (auto logger = fuchsia_logging::Logger::Create(get_default_settings(), &min_severity_);
logger.is_ok()) {
global_instance_ = new Logger(*std::move(logger));
} else {
global_instance_ = new Logger;
}
});
return *global_instance_;
}
zx::result<> FlushSpan(cpp20::span<const uint8_t> span) const { return logger().FlushSpan(span); }
template <typename T>
void ForEachTag(T callback) const {
logger().ForEachTag(callback);
}
static FuchsiaLogSeverity min_severity() { return min_severity_.load(std::memory_order_relaxed); }
private:
Logger() = default;
explicit Logger(fuchsia_logging::Logger logger) : logger_(std::move(logger)) {}
fuchsia_logging::Logger logger() const {
std::scoped_lock lock(mutex_);
return logger_;
}
static std::once_flag once_;
static Logger* global_instance_;
static std::atomic<FuchsiaLogSeverity> min_severity_;
mutable std::mutex mutex_;
fuchsia_logging::Logger logger_ __TA_GUARDED(mutex_);
};
std::once_flag Logger::once_;
Logger* Logger::global_instance_;
std::atomic<FuchsiaLogSeverity> Logger::min_severity_;
#endif
extern "C" {
__EXPORT
zx_koid_t FuchsiaLogGetCurrentThreadKoid() {
if (unlikely(tls_thread_koid == ZX_KOID_INVALID)) {
tls_thread_koid = GetKoid(zx_thread_self());
}
ZX_DEBUG_ASSERT(tls_thread_koid != ZX_KOID_INVALID);
return tls_thread_koid;
}
#if FUCHSIA_API_LEVEL_LESS_THAN(NEXT)
// FuchsiaLogSetStateLocked, FuchsiaLogAcquireState, FuchsiaLogReleaseState and
// FuchsiaLogGetStateLocked can can be removed once the API level mentioned above and all preceding
// levels, have been retired.
#endif
__EXPORT
void FuchsiaLogSetStateLocked(LogState* new_state) { state = new_state; }
__EXPORT void FuchsiaLogAcquireState() __TA_NO_THREAD_SAFETY_ANALYSIS { state_lock.lock(); }
__EXPORT void FuchsiaLogReleaseState() __TA_NO_THREAD_SAFETY_ANALYSIS { state_lock.unlock(); }
__EXPORT
LogState* FuchsiaLogGetStateLocked() { return state; }
#if FUCHSIA_API_LEVEL_AT_LEAST(NEXT)
__EXPORT
void FuchsiaLogInitGlobalLogger(const RawLogSettings* settings) {
Logger::InitGlobalInstance(*settings);
}
__EXPORT uint8_t FuchsiaLogGetGlobalMinSeverity() { return Logger::min_severity(); }
__EXPORT
Logger* FuchsiaLogGetGlobalLogger(RawLogSettings (*get_default_settings)()) {
return &Logger::GlobalInstance(get_default_settings);
}
__EXPORT
zx_status_t FuchsiaLogWrite(const Logger* logger, const void* buffer, size_t len) {
return logger->FlushSpan(cpp20::span(static_cast<const uint8_t*>(buffer), len)).status_value();
}
__EXPORT
void FuchsiaLogForEachTag(const Logger* logger, void* context,
void (*callback)(void* context, const char* tag)) {
logger->ForEachTag(
[callback, context](const std::string& tag) { callback(context, tag.c_str()); });
}
#endif // FUCHSIA_API_LEVEL_AT_LEAST(NEXT)
} // extern "C"
} // namespace fuchsia_logging::internal