From 658a0dab4b6415a4abf93bba4054688558a20701 Mon Sep 17 00:00:00 2001 From: Jens Alfke Date: Sun, 26 Nov 2023 10:33:47 -0800 Subject: [PATCH] Logger -> MiniLogger; made less dependent on Crouton --- CMakeLists.txt | 4 +- crouton.xcodeproj/project.pbxproj | 12 +-- include/crouton/util/Bytes.hh | 2 +- include/crouton/util/Logging.hh | 6 +- include/crouton/util/MiniFormat.hh | 24 ++++-- .../crouton/util/{Logger.hh => MiniLogger.hh} | 46 ++++++++--- include/crouton/util/MiniOStream.hh | 69 +++++++++++----- src/io/esp32/CMakeLists.txt | 2 +- src/support/MiniFormat.cc | 8 +- src/support/{Logger.cc => MiniLogger.cc} | 79 +++++++++---------- src/support/MiniOStream.cc | 7 +- 11 files changed, 163 insertions(+), 96 deletions(-) rename include/crouton/util/{Logger.hh => MiniLogger.hh} (65%) rename src/support/{Logger.cc => MiniLogger.cc} (77%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0cf1f5e..1274c38 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -142,10 +142,10 @@ add_library( LibCrouton STATIC src/support/Backtrace+Unix.cc src/support/Backtrace+Windows.cc src/support/betterassert.cc - src/support/Memoized.cc - src/support/Logger.cc src/support/Logging.cc + src/support/Memoized.cc src/support/MiniFormat.cc + src/support/MiniLogger.cc src/support/MiniOStream.cc src/support/StringUtils.cc src/support/Varint.cc diff --git a/crouton.xcodeproj/project.pbxproj b/crouton.xcodeproj/project.pbxproj index f2e66f0..6e13b6a 100644 --- a/crouton.xcodeproj/project.pbxproj +++ b/crouton.xcodeproj/project.pbxproj @@ -149,7 +149,7 @@ 27BCD3382AF30A20009DFCED /* libmbedcrypto.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27BCD3352AF30A20009DFCED /* libmbedcrypto.a */; }; 27E98EDF2AC2099E002F3D35 /* test_generator.cc in Sources */ = {isa = PBXBuildFile; fileRef = 27E98EDE2AC2099E002F3D35 /* test_generator.cc */; }; 27E9A0C72AFAB8FE00EF3726 /* Task.cc in Sources */ = {isa = PBXBuildFile; fileRef = 27E9A0C62AFAB8FE00EF3726 /* Task.cc */; }; - 27E9A0D62AFDAA6100EF3726 /* Logger.cc in Sources */ = {isa = PBXBuildFile; fileRef = 27E9A0D52AFDAA6100EF3726 /* Logger.cc */; }; + 27E9A0D62AFDAA6100EF3726 /* MiniLogger.cc in Sources */ = {isa = PBXBuildFile; fileRef = 27E9A0D52AFDAA6100EF3726 /* MiniLogger.cc */; }; 27E9A1122B02C61A00EF3726 /* miniz_tinfl.c in Sources */ = {isa = PBXBuildFile; fileRef = 27E9A10B2B02C52C00EF3726 /* miniz_tinfl.c */; settings = {COMPILER_FLAGS = "-Wno-comma -O3"; }; }; 27E9A1162B02CD1800EF3726 /* miniz_tdef.c in Sources */ = {isa = PBXBuildFile; fileRef = 27E9A0E72B02C52C00EF3726 /* miniz_tdef.c */; settings = {COMPILER_FLAGS = "-Wno-comma -O3"; }; }; 27E9A1172B02CF9A00EF3726 /* miniz.c in Sources */ = {isa = PBXBuildFile; fileRef = 27E9A0E22B02C52C00EF3726 /* miniz.c */; settings = {COMPILER_FLAGS = "-Wno-comma -O3"; }; }; @@ -715,8 +715,8 @@ 27E98EDE2AC2099E002F3D35 /* test_generator.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = test_generator.cc; sourceTree = ""; }; 27E98EE02AC21940002F3D35 /* Awaitable.hh */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Awaitable.hh; sourceTree = ""; }; 27E9A0C62AFAB8FE00EF3726 /* Task.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Task.cc; sourceTree = ""; }; - 27E9A0D42AFDA91200EF3726 /* Logger.hh */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Logger.hh; sourceTree = ""; }; - 27E9A0D52AFDAA6100EF3726 /* Logger.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Logger.cc; sourceTree = ""; }; + 27E9A0D42AFDA91200EF3726 /* MiniLogger.hh */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = MiniLogger.hh; sourceTree = ""; }; + 27E9A0D52AFDAA6100EF3726 /* MiniLogger.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MiniLogger.cc; sourceTree = ""; }; 27E9A0E12B02C52C00EF3726 /* miniz_zip.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = miniz_zip.h; sourceTree = ""; }; 27E9A0E22B02C52C00EF3726 /* miniz.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = miniz.c; sourceTree = ""; }; 27E9A0E32B02C52C00EF3726 /* miniz_tinfl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = miniz_tinfl.h; sourceTree = ""; }; @@ -1183,8 +1183,8 @@ 27B3306A2AB391F30066C8DA /* Bytes.hh */, 2727304B2A8E811B000CCA22 /* Defer.hh */, 277E8A432ABA50FB00E78CB1 /* LinkedList.hh */, - 27E9A0D42AFDA91200EF3726 /* Logger.hh */, 278F7F222AAA98FE005B12F2 /* Logging.hh */, + 27E9A0D42AFDA91200EF3726 /* MiniLogger.hh */, 277B6C272AE06CDA006F053D /* MiniFormat.hh */, 2755E81C2B0947D40005AC35 /* MiniOStream.hh */, 277B65282AD766EF006F053D /* Relation.hh */, @@ -1622,11 +1622,11 @@ 27F49CD42A9E4E8E00BFB24C /* Backtrace.hh */, 277B652B2AD8B5D8006F053D /* betterassert.cc */, 27B330692AB388960066C8DA /* Endian.hh */, - 27E9A0D52AFDAA6100EF3726 /* Logger.cc */, 278F7F232AAA98FE005B12F2 /* Logging.cc */, 275A5F132AAFB3B1009791E8 /* Memoized.hh */, 275A5F142AAFB3B1009791E8 /* Memoized.cc */, 277B6C282AE06CDA006F053D /* MiniFormat.cc */, + 27E9A0D52AFDAA6100EF3726 /* MiniLogger.cc */, 2755E81D2B0947D40005AC35 /* MiniOStream.cc */, 278F7E3E2AA24FEE005B12F2 /* StringUtils.hh */, 27B330572AB278870066C8DA /* StringUtils.cc */, @@ -1999,7 +1999,7 @@ 272730482A8D8A73000CCA22 /* Scheduler.cc in Sources */, 2755E81F2B0947D40005AC35 /* MiniOStream.cc in Sources */, 277B652C2AD8B5D8006F053D /* betterassert.cc in Sources */, - 27E9A0D62AFDAA6100EF3726 /* Logger.cc in Sources */, + 27E9A0D62AFDAA6100EF3726 /* MiniLogger.cc in Sources */, 272730532A8EC61D000CCA22 /* FileStream.cc in Sources */, 272A852B2A97B2090083D947 /* HTTPConnection.cc in Sources */, 2727304E2A8E9D99000CCA22 /* UVBase.cc in Sources */, diff --git a/include/crouton/util/Bytes.hh b/include/crouton/util/Bytes.hh index f482abc..ca3f66a 100644 --- a/include/crouton/util/Bytes.hh +++ b/include/crouton/util/Bytes.hh @@ -55,7 +55,7 @@ namespace crouton { /** Low-level struct pointing to immutable data. - Usually serves as the source of a `write`, or as a returned buffer from `readNoCopy`. */ + Usually serves as the source of a `write`, or as a returned buffer from `readNoCopy`. */ class ConstBytes : public Bytes { public: using Bytes::Bytes; diff --git a/include/crouton/util/Logging.hh b/include/crouton/util/Logging.hh index 9b79877..e268c22 100644 --- a/include/crouton/util/Logging.hh +++ b/include/crouton/util/Logging.hh @@ -18,7 +18,7 @@ #pragma once -// By default, Crouton uses its own small logging library, defined in Logger.hh. +// By default, Crouton uses its own small logging library, defined in MiniLogger.hh. // To make it use spdlog instead, pre-define the macro `CROUTON_USE_SPDLOG` to `1`. #ifndef CROUTON_USE_SPDLOG #define CROUTON_USE_SPDLOG 0 @@ -31,13 +31,15 @@ #include #include // Makes custom types loggable via `operator <<` overloads #else -#include "crouton/util/Logger.hh" +#include "crouton/util/MiniLogger.hh" #endif namespace crouton { #if CROUTON_USE_SPDLOG namespace log = ::spdlog; +#else + namespace log = ::crouton::mini; #endif diff --git a/include/crouton/util/MiniFormat.hh b/include/crouton/util/MiniFormat.hh index 0628c8e..7bfe699 100644 --- a/include/crouton/util/MiniFormat.hh +++ b/include/crouton/util/MiniFormat.hh @@ -27,6 +27,20 @@ /* A string formatting API mostly compatible with `std::format`, but optimized for small code size. https://en.cppreference.com/w/cpp/utility/format/formatter + + Missing functionality and limitations: + - You can't create custom formatters that interpret custom field specs. (But you can format + custom types by implementing `operator<<`.) + - Arguments can't be reordered (i.e. a field spec like `{nn:}` isn't allowed.) + - Field widths & alignment are not Unicode-aware; they assume 1 byte == 1 space. + - Localized variants are unimplemented (using 'L' in a format spec has no effect.) + - Only 10 arguments are allowed. (You can change this by changing BaseFormatString::kMaxSpecs.) + - Field width and precision are limited to 255. + + Known bugs: + - When a number is zero-padded, the zeroes go before the sign character, not afterward. + - When the alternate ('#') form of a float adds a decimal point, it will go after any exponent, + when it should go before. */ namespace crouton::mini { @@ -107,7 +121,7 @@ namespace crouton::mini { /** A pointer to a C array of argument types, terminated with `None`. - This is constructed at compile-time and passed to the `format` implementation.*/ + This is constructed at compile-time and passed to the `format` implementation. */ using ArgTypeList = i::ArgType const*; @@ -213,8 +227,8 @@ namespace crouton::mini { Spec const* _pSpec; }; - iterator begin() const Pure {return iterator(*this);} - iterator end() const Pure {return iterator(&_impl._lengths[_impl._nSegments]);} + iterator begin() const {return iterator(*this);} + iterator end() const {return iterator(&_impl._lengths[_impl._nSegments]);} #ifndef NDEBUG static BaseFormatString testParse(const char* cstr, ArgTypeList argTypes) { @@ -222,8 +236,8 @@ namespace crouton::mini { } #endif private: - static constexpr size_t kMaxSegments = 15; - static constexpr size_t kMaxSpecs = 8; + static constexpr size_t kMaxSpecs = 10; + static constexpr size_t kMaxSegments = 2 * kMaxSpecs + 1; struct Impl { const char* const _str; // the format string diff --git a/include/crouton/util/Logger.hh b/include/crouton/util/MiniLogger.hh similarity index 65% rename from include/crouton/util/Logger.hh rename to include/crouton/util/MiniLogger.hh index 61fe4b4..de53579 100644 --- a/include/crouton/util/Logger.hh +++ b/include/crouton/util/MiniLogger.hh @@ -1,5 +1,5 @@ // -// Logger.hh +// MiniLogger.hh // // Copyright 2023-Present Couchbase, Inc. All rights reserved. // @@ -16,16 +16,13 @@ // limitations under the License. // -#if CROUTON_USE_SPDLOG != 0 -#error "Don't include Logger.hh directly; include Logging.hh instead" -#endif - #pragma once -#include "crouton/util/Base.hh" #include "crouton/util/MiniFormat.hh" #include -namespace crouton::log { +namespace crouton::mini { + using std::string; + using std::string_view; // Minimal logging API, mostly compatible with spdlog @@ -36,24 +33,37 @@ namespace crouton::log { }; + /** A named logger, which can have its own level. */ class logger { public: - logger(string name, level::level_enum level); + /// Constructs a logger with a name and a default initial level. + logger(string name, level::level_enum defaultLevel); ~logger() = delete; - string const& name() const Pure {return _name;} - level::level_enum level() const Pure {return _level;} + /// The logger's name. + string const& name() const {return _name;} + + /// The logger's current level. Messages with a lower level will not be logged. + level::level_enum level() const {return _level;} + + /// Sets the current level. void set_level(level::level_enum level) {_level = level;} - bool should_log(level::level_enum level) const Pure {return level >= _level;} + /// Returns true if the logger will log messages at the given level. + bool should_log(level::level_enum level) const {return level >= _level;} + + /// Logs a formatted message at the given level. template void log(level::level_enum lvl, mini::FormatString const& fmt, Args &&...args) { if (should_log(lvl)) [[unlikely]] _log(lvl, fmt, mini::ArgTypes::ids, mini::i::passArg(args)...); } + /// Logs an unformatted message at the given level. void log(level::level_enum lvl, string_view msg); + // The methods below all call `log` with the levels indicated by their names. + template void trace(mini::FormatString const& fmt, Args &&...args) { log(level::trace, fmt, std::forward(args)...); @@ -90,15 +100,29 @@ namespace crouton::log { } void critical(string_view msg) {log(level::critical, msg);} + /// Initializes levels based on the value of the `CROUTON_LOG_LEVEL` environment variable. + /// @note This just calls `load_env_levels(getenv("CROUTON_LOG_LEVEL"))`. + /// @note This function isn't available on ESP32 since it has no environment API. static void load_env_levels(); + + /// Initializes levels based on the given string. + /// - First, the string is split into sections at commas. + /// - A section of the form "name=levelname" sets the level of the named logger. + /// - If no logger with that name exists yet, the level will be set when it's created. + /// - A section that's just "levelname" applies to all loggers that aren't explicitly named. static void load_env_levels(const char *envValue); + /// Returns the logger with the given name, else nullptr. static logger* get(string_view name); + /// Calls a function on every logger. static void apply_all(std::function); using Sink = void (*)(logger const&, level::level_enum, string_view) noexcept; + /// Registers a function that handles log messages. + /// If non-null, every log message triggers a call to this function, instead of the + /// default behavior of writing to `stderr`. static void set_output(Sink); private: diff --git a/include/crouton/util/MiniOStream.hh b/include/crouton/util/MiniOStream.hh index 765dbce..9338223 100644 --- a/include/crouton/util/MiniOStream.hh +++ b/include/crouton/util/MiniOStream.hh @@ -17,18 +17,32 @@ // #pragma once -#include "crouton/util/Bytes.hh" #include #include +#include #include +#include +#include + +#if __has_include("betterassert.hh") +#include "betterassert.hh" +#else +#include +#endif /* Lightweight replacement for std::ostream. */ namespace crouton::mini { + using string = std::string; + using string_view = std::string_view; +#ifdef _WIN32 + static constexpr const char* endl = "\n\r"; +#else static constexpr const char* endl = "\n"; +#endif /** Abstract base class of output streams. */ class ostream { @@ -38,7 +52,8 @@ namespace crouton::mini { ostream& write(const char* begin, const char* end) {return write(begin, end - begin);} - ostream& write(ConstBytes b); + ostream& write(std::span b); + ostream& write(std::span b); ostream& write(const char* str); ostream& write(string const& str); @@ -59,30 +74,32 @@ namespace crouton::mini { class stringstream final : public ostream { public: stringstream() = default; - stringstream(std::string s) :_str(std::move(s)) { } + stringstream(string s) :_str(std::move(s)) { } ostream& write(const char* src, size_t len) override {_str.append(src, len); return *this;} - string const& str() const & {return _str;} - string&& str() && {return std::move(_str);} - string extract_str() {return std::move(_str);} + string const& str() const & {return _str;} + string str() && {return std::move(_str);} template void str(T&& s) {_str = std::forward(s);} + string_view view() const {return _str;} + void clear() {_str.clear();} private: - std::string _str; + string _str; }; /** ostream that writes to a fixed-size caller-provided buffer. */ - class bufferstream final : public ostream { + class bufstream : public ostream { public: - bufferstream(char* begin, char* end) - :_begin(begin), _next(begin), _end(end) {assert(_end >= _begin); } - explicit bufferstream(MutableBytes b) :bufferstream((char*)b.data(), (char*)b.endByte()) { } + bufstream(char* begin, char* end) + :_begin(begin), _next(begin), _end(end) {assert(_end >= _begin); } + bufstream(char* begin, size_t size) :bufstream(begin, begin + size) { } + explicit bufstream(std::span b) :bufstream(b.data(), b.size_bytes()) { } ostream& write(const char* src, size_t len) override { if (_next + len > _end) @@ -92,19 +109,32 @@ namespace crouton::mini { return *this; } - size_t available() const Pure {return _end - _next;} + size_t available() const {return _end - _next;} - string_view str() const Pure {return {_begin, _next};} - MutableBytes bytes() const Pure {return {_begin, _next};} - MutableBytes buffer() const Pure {return {_begin, _end};} + string_view str() const {return {_begin, _next};} + std::span buffer() const {return {_begin, _end};} void clear() {_next = _begin;} - private: + protected: + bufstream() = default; char *_begin, *_next, *_end; }; + /** ostream that writes to a fixed-size buffer it allocates itself. + A small buffer lives inside the object; a large one is heap-allocated. */ + template + class owned_bufstream : public bufstream { + public: + owned_bufstream() :bufstream(SIZE > kMaxInlSize ? new char[SIZE] : _buffer, SIZE) { } + ~owned_bufstream() {if constexpr (SIZE > kMaxInlSize) delete[] _begin;} + private: + static constexpr size_t kMaxInlSize = 64; + char _buffer[ (SIZE <= kMaxInlSize) ? SIZE : 1 ]; + }; + + /** Minimalist file stream suitable for cout and cerr. */ class fdstream final : public ostream { public: @@ -117,13 +147,14 @@ namespace crouton::mini { /** ostream that writes to stdout. */ extern fdstream cout; + /** ostream that writes to stderr. */ extern fdstream cerr; - inline ostream& operator<< (ostream& o, ConstBytes bytes) {return o.write(bytes);} + inline ostream& operator<< (ostream& o, std::span bytes) {return o.write(bytes);} inline ostream& operator<< (ostream& o, const char* str) {return o.write(str);} - inline ostream& operator<< (ostream& o, string_view str) {return o.write(str);} + inline ostream& operator<< (ostream& o, string_view str) {return o.write(str.data(), str.size());} inline ostream& operator<< (ostream& o, string const& str) {return o.write(str);} inline ostream& operator<< (ostream& o, char c) {return o.write(&c, 1);} @@ -133,7 +164,7 @@ namespace crouton::mini { ostream& operator<< (ostream& o, INT i) {return o.writeInt64(int64_t(i));} template - ostream& operator<< (ostream& o, UINT i) {return o.writeInt64(uint64_t(i));} + ostream& operator<< (ostream& o, UINT i) {return o.writeUInt64(uint64_t(i));} inline ostream& operator<< (ostream& o, float f) {return o.writeDouble(f);} inline ostream& operator<< (ostream& o, double d) {return o.writeDouble(d);} diff --git a/src/io/esp32/CMakeLists.txt b/src/io/esp32/CMakeLists.txt index 5541b5c..ceaa4c4 100644 --- a/src/io/esp32/CMakeLists.txt +++ b/src/io/esp32/CMakeLists.txt @@ -24,10 +24,10 @@ idf_component_register( "${src}/io/mbed/TLSSocket.cc" "${src}/support/Backtrace.cc" "${src}/support/betterassert.cc" - "${src}/support/Logger.cc" "${src}/support/Logging.cc" "${src}/support/Memoized.cc" "${src}/support/MiniFormat.cc" + "${src}/support/MiniLogger.cc" "${src}/support/MiniOStream.cc" "${src}/support/StringUtils.cc" "${src}/support/Varint.cc" diff --git a/src/support/MiniFormat.cc b/src/support/MiniFormat.cc index bb453d8..764613c 100644 --- a/src/support/MiniFormat.cc +++ b/src/support/MiniFormat.cc @@ -51,8 +51,8 @@ namespace crouton::mini { // non-localized ASCII-specific equivalents of ctypes: - static Pure bool isupper(char c) {return c >= 'A' && c <= 'Z';} - static Pure char toupper(char c) {return (c >= 'a' && c <= 'z') ? (c - 32) : c;} + static bool isupper(char c) {return c >= 'A' && c <= 'Z';} + static char toupper(char c) {return (c >= 'a' && c <= 'z') ? (c - 32) : c;} static void upperize(char *begin, char *end) { for (char *c = begin; c != end; ++c) @@ -263,7 +263,7 @@ namespace crouton::mini { // General case. First format to a string: stringstream buf; vformat_arg_nowidth(buf, spec, itype, args); - string str = buf.extract_str(); + string str = std::move(buf).str(); size_t s = str.size(); if (s >= spec.width) { @@ -307,7 +307,7 @@ namespace crouton::mini { string vformat_types(BaseFormatString const& fmt, ArgTypeList types, va_list args) { stringstream out; vformat_types_to(out, fmt, types, args); - return out.extract_str(); + return std::move(out).str(); } diff --git a/src/support/Logger.cc b/src/support/MiniLogger.cc similarity index 77% rename from src/support/Logger.cc rename to src/support/MiniLogger.cc index 32ab95c..db7e433 100644 --- a/src/support/Logger.cc +++ b/src/support/MiniLogger.cc @@ -16,11 +16,9 @@ // limitations under the License. // -#include "crouton/util/Logging.hh" - #if ! CROUTON_USE_SPDLOG -#include "crouton/util/Logger.hh" +#include "crouton/util/MiniLogger.hh" #include "crouton/io/Process.hh" #include "support/StringUtils.hh" @@ -33,12 +31,9 @@ # include # include # include -# include "crouton/util/MiniOStream.hh" #endif -namespace crouton::log { - using namespace std; - using namespace crouton::mini; +namespace crouton::mini { static constexpr string_view kLevelName[] = { "trace", "debug", "info", "warn", "error", "critical", "off" @@ -48,8 +43,8 @@ namespace crouton::log { }; - static mutex sLogMutex; // Thread-safety & prevents overlapping msgs - static vector* sLoggers; // All registered Loggers + static std::mutex sLogMutex; // Thread-safety & prevents overlapping msgs + static std::vector* sLoggers; // All registered Loggers static logger::Sink sLogSink = nullptr; // Optional function to write messages static const char* sEnvLevelsStr; @@ -59,16 +54,16 @@ namespace crouton::log { logger::logger(string name, level::level_enum level) :_name(std::move(name)) ,_level(level) { - unique_lock lock(sLogMutex); + std::unique_lock lock(sLogMutex); load_env_level(); if (!sLoggers) - sLoggers = new vector; + sLoggers = new std::vector; sLoggers->push_back(this); } logger* logger::get(string_view name) { - unique_lock lock(sLogMutex); + std::unique_lock lock(sLogMutex); if (sLoggers) { for (auto logger : *sLoggers) if (logger->name() == name) @@ -79,7 +74,7 @@ namespace crouton::log { void logger::apply_all(std::function fn) { - unique_lock lock(sLogMutex); + std::unique_lock lock(sLogMutex); if (sLoggers) { for (auto logger : *sLoggers) fn(*logger); @@ -88,7 +83,7 @@ namespace crouton::log { void logger::set_output(logger::Sink sink) { - unique_lock lock(sLogMutex); + std::unique_lock lock(sLogMutex); sLogSink = sink; } @@ -100,12 +95,12 @@ namespace crouton::log { return level::level_enum(level); ++level; } - return log::level::info; // default if unrecognized name + return level::info; // default if unrecognized name } void logger::load_env_levels(const char *envValue) { - unique_lock lock(sLogMutex); + std::unique_lock lock(sLogMutex); if (!sEnvLevelsStr) sEnvLevelsStr = strdup(envValue ? envValue : ""); for (auto logger : *sLoggers) @@ -131,6 +126,9 @@ namespace crouton::log { } +#pragma mark - NON-ESP32 METHODS: + + #ifndef ESP_PLATFORM static time_t sTime; // Time in seconds that's formatted in sTimeBuf static char sTimeBuf[30]; // Formatted timestamp, to second accuracy @@ -161,14 +159,14 @@ namespace crouton::log { } const char* color = ""; - if (lvl >= log::level::err) + if (lvl >= level::err) color = tty.red; - else if (lvl == log::level::warn) + else if (lvl == level::warn) color = tty.yellow; - fprintf(stderr, "%s%06ld%s %s%s| <%s> ", - sTimeBuf, now.tv_nsec / 1000, tty.reset, - color, kLevelDisplayName[int(lvl)], _name.c_str()); + format_to(cerr, "{}{:06d}{} {}{}| <{}> ", + sTimeBuf, now.tv_nsec / 1000, tty.reset, + color, kLevelDisplayName[int(lvl)], _name); } @@ -177,7 +175,7 @@ namespace crouton::log { if (auto sink = sLogSink) { sink(*this, lvl, msg); } else { - unique_lock lock(sLogMutex); + std::unique_lock lock(sLogMutex); _writeHeader(lvl); cerr << msg << io::TTY::err().reset << endl; } @@ -185,26 +183,23 @@ namespace crouton::log { } - void logger::_log(level::level_enum lvl, BaseFormatString const& fmt, mini::ArgTypeList types, ...) { + void logger::_log(level::level_enum lvl, BaseFormatString const& fmt, ArgTypeList types, ...) { + va_list args; + va_start(args, types); if (auto sink = sLogSink) { - stringstream out; - va_list args; - va_start(args, types); - mini::vformat_types_to(out, fmt, types, args); - va_end(args); - sink(*this, lvl, out.str()); + sink(*this, lvl, vformat_types(fmt, types, args)); } else { - unique_lock lock(sLogMutex); - + std::unique_lock lock(sLogMutex); _writeHeader(lvl); - va_list args; - va_start(args, types); - mini::vformat_types_to(cerr, fmt, types, args); - va_end(args); + vformat_types_to(cerr, fmt, types, args); cerr << io::TTY::err().reset << endl; } + va_end(args); } + +#pragma mark - ESP32 METHODS + #else // ESP_PLATFORM static constexpr esp_log_level_t kESPLevel[] = { @@ -221,11 +216,11 @@ namespace crouton::log { io::TTY const& tty = io::TTY::err(); const char* color; switch (lvl) { - case log::level::critical: - case log::level::err: color = tty.red; break; - case log::level::warn: color = tty.yellow; break; - case log::level::debug: - case log::level::trace: color = tty.dim; break; + case level::critical: + case level::err: color = tty.red; break; + case level::warn: color = tty.yellow; break; + case level::debug: + case level::trace: color = tty.dim; break; default: color = ""; break; } #if CONFIG_LOG_TIMESTAMP_SOURCE_RTOS @@ -249,10 +244,10 @@ namespace crouton::log { } - void logger::_log(level::level_enum lvl, BaseFormatString const& fmt, mini::ArgTypeList types, ...) { + void logger::_log(level::level_enum lvl, BaseFormatString const& fmt, ArgTypeList types, ...) { va_list args; va_start(args, types); - string message = mini::vformat_types(fmt, types, args); + string message = vformat_types(fmt, types, args); va_end(args); log(lvl, message); } diff --git a/src/support/MiniOStream.cc b/src/support/MiniOStream.cc index 2e2f9f1..b2fd971 100644 --- a/src/support/MiniOStream.cc +++ b/src/support/MiniOStream.cc @@ -21,13 +21,15 @@ #include namespace crouton::mini { + fdstream cout(stdout); fdstream cerr(stderr); - ostream& ostream::write(ConstBytes b) {return write((const char*)b.data(), b.size());} + ostream& ostream::write(std::span b){return write(b.data(), b.size());} + ostream& ostream::write(std::span b){return write((const char*)b.data(), b.size());} ostream& ostream::write(const char* str) {return write(str, strlen(str));} - ostream& ostream::write(string const& str) {return write(str.data(), str.size());} + ostream& ostream::write(std::string const& str) {return write(str.data(), str.size());} ostream& ostream::writeInt64(int64_t i, int base) { char buf[20]; @@ -47,7 +49,6 @@ namespace crouton::mini { if (__builtin_available(macOS 13.3, iOS 16.3, tvOS 16.3, watchOS 9.3, *)) { #endif auto result = std::to_chars(&buf[0], &buf[sizeof(buf)], f); - assert(result.ec == std::errc{}); return write(&buf[0], result.ptr - buf); #ifdef __APPLE__ } else {