blob: 8e51230ccbfe0b2f66ba1ec789331c7ddaa54d1d [file] [log] [blame]
// Copyright 2021 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.
#ifndef LIB_DRIVER2_LOGGER_INTERNAL_H_
#define LIB_DRIVER2_LOGGER_INTERNAL_H_
#include <lib/driver2/logger.h>
namespace driver_internal {
static inline cpp17::optional<cpp17::string_view> FromCString(const char* value) {
if (value) {
return cpp17::optional(value);
}
return cpp17::nullopt;
}
template <typename... Args>
constexpr size_t ArgsSize(Args... args) {
return sizeof...(args);
}
template <typename... Args>
struct Tuplet {
std::tuple<Args...> tuple;
size_t size;
constexpr Tuplet(std::tuple<Args...> tuple, size_t size) : tuple(tuple), size(size) {}
};
template <typename Key, typename Value>
struct KeyValue {
Key key;
Value value;
constexpr KeyValue(Key key, Value value) : key(key), value(value) {}
};
template <size_t i, size_t size>
constexpr bool ILessThanSize() {
return i < size;
}
template <bool expr>
constexpr bool Not() {
return !expr;
}
template <typename... LogArgs>
constexpr driver_internal::Tuplet<LogArgs...> Args(LogArgs... values) {
return driver_internal::Tuplet<LogArgs...>(std::make_tuple(values...), sizeof...(values));
}
template <typename Key, typename Value>
constexpr driver_internal::KeyValue<Key, Value> KeyValueInternal(Key key, Value value) {
return driver_internal::KeyValue<Key, Value>(key, value);
}
struct EncoderState {
fuchsia_syslog::LogBuffer buffer;
// Does nothing (enabled when we hit the last parameter that the user passed into us)
template <size_t i, size_t size, typename... T,
typename std::enable_if<Not<ILessThanSize<i, size>()>(), int>::type = 0>
void Encode(Tuplet<T...> value) {}
// Encodes an int64
void Encode(KeyValue<const char*, int64_t> value) {
buffer.WriteKeyValue(value.key, value.value);
}
// Encodes an int
void Encode(KeyValue<const char*, int> value) {
Encode(KeyValue<const char*, int64_t>(value.key, value.value));
}
// Encodes a uint64
void Encode(KeyValue<const char*, uint64_t> value) {
buffer.WriteKeyValue(value.key, value.value);
}
// Encodes an unsigned int
void Encode(KeyValue<const char*, unsigned int> value) {
Encode(KeyValue<const char*, uint64_t>(value.key, value.value));
}
// Encodes a NULL-terminated C-string.
void Encode(KeyValue<const char*, const char*> value) {
buffer.WriteKeyValue(value.key, value.value);
}
// Encodes a double floating point value
void Encode(KeyValue<const char*, double> value) { buffer.WriteKeyValue(value.key, value.value); }
// Encodes a floating point value
void Encode(KeyValue<const char*, float> value) { buffer.WriteKeyValue(value.key, value.value); }
// Encodes a boolean value
void Encode(KeyValue<const char*, bool> value) { buffer.WriteKeyValue(value.key, value.value); }
// Encodes an arbitrary list of values recursively.
template <size_t i, size_t size, typename... T,
typename std::enable_if<ILessThanSize<i, size>(), int>::type = 0>
void Encode(Tuplet<T...> value) {
auto val = std::get<i>(value.tuple);
Encode(val);
Encode<i + 1, size>(value);
}
};
template <typename Msg, typename... KeyValuePairs>
struct LogValue {
constexpr LogValue(Msg msg, Tuplet<KeyValuePairs...> kvps) : msg(msg), kvps(kvps) {}
void LogNew(driver::Logger& logger, FuchsiaLogSeverity severity, const char* file,
unsigned int line, const char* condition) const {
EncoderState state;
uint32_t dropped = logger.GetAndResetDropped();
logger.BeginRecord(state.buffer, severity, FromCString(file), line, FromCString(msg),
FromCString(condition), false, dropped);
// https://bugs.llvm.org/show_bug.cgi?id=41093 -- Clang loses constexpr
// even though this should be constexpr here.
state.Encode<0, sizeof...(KeyValuePairs)>(kvps);
logger.FlushRecord(state.buffer, dropped);
}
Msg msg;
driver_internal::Tuplet<KeyValuePairs...> kvps;
};
template <typename Msg, typename... Args>
static auto MakeValue(Msg msg, driver_internal::Tuplet<Args...> args) {
return LogValue<Msg, Args...>(msg, args);
}
template <size_t i, size_t size, typename... Values, typename... Tuple,
typename std::enable_if<driver_internal::Not<driver_internal::ILessThanSize<i, size>()>(),
int>::type = 0>
static auto MakeKV(std::tuple<Values...> value, std::tuple<Tuple...> tuple) {
return driver_internal::Tuplet<Tuple...>(tuple, size);
}
template <size_t i, size_t size, typename... Values, typename... Tuple,
typename std::enable_if<driver_internal::ILessThanSize<i, size>(), int>::type = 0>
static auto MakeKV(std::tuple<Values...> value, std::tuple<Tuple...> tuple) {
// Key at index i, value at index i+1
auto k = std::get<i>(value);
auto v = std::get<i + 1>(value);
auto new_tuple = std::tuple_cat(tuple, std::make_tuple(KeyValueInternal(k, v)));
return MakeKV<i + 2, size, Values...>(value, new_tuple);
}
template <typename... Args, typename... EmptyTuple>
static auto MakeKV(std::tuple<Args...> args, std::tuple<EmptyTuple...> start_tuple) {
return MakeKV<0, sizeof...(Args), Args..., EmptyTuple...>(args, start_tuple);
}
template <typename... Args>
static auto MakeKV(std::tuple<Args...> args) {
return MakeKV(args, std::make_tuple());
}
template <typename Msg, typename... Args>
static void fx_slog(driver::Logger& logger, FuchsiaLogSeverity severity, const char* file, int line,
Msg msg, Args... args) {
if (severity < logger.GetSeverity()) {
return;
}
MakeValue(msg, MakeKV<Args...>(std::make_tuple(args...)))
.LogNew(logger, severity, file, line, nullptr);
}
} // namespace driver_internal
#endif // LIB_DRIVER2_LOGGER_INTERNAL_H_