-
-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add spdlog sink for bedrock log integration
- Loading branch information
1 parent
52bf438
commit 62ed16e
Showing
9 changed files
with
307 additions
and
73 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// Copyright (c) 2024, The Endstone Project. (https://endstone.dev) All Rights Reserved. | ||
// | ||
// 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. | ||
|
||
#pragma once | ||
|
||
#include <spdlog/pattern_formatter.h> | ||
#include <spdlog/spdlog.h> | ||
|
||
class BedrockLevelFormatter : public spdlog::custom_flag_formatter { | ||
public: | ||
void format(const spdlog::details::log_msg &msg, const std::tm &, spdlog::memory_buf_t &dest) override; | ||
|
||
[[nodiscard]] std::unique_ptr<custom_flag_formatter> clone() const override; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
// Copyright (c) 2024, The Endstone Project. (https://endstone.dev) All Rights Reserved. | ||
// | ||
// 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. | ||
|
||
#pragma once | ||
|
||
#include <array> | ||
#include <string_view> | ||
|
||
#include <spdlog/details/console_globals.h> | ||
#include <spdlog/details/os.h> | ||
#include <spdlog/sinks/base_sink.h> | ||
#include <spdlog/spdlog.h> | ||
|
||
class BedrockLogSink : public spdlog::sinks::base_sink<spdlog::details::console_mutex::mutex_t> { | ||
public: | ||
explicit BedrockLogSink(FILE *target_file, spdlog::color_mode mode = spdlog::color_mode::automatic); | ||
void set_color_mode(spdlog::color_mode mode); | ||
|
||
protected: | ||
void sink_it_(const spdlog::details::log_msg &msg) override; | ||
void flush_() override; | ||
|
||
public: | ||
// Formatting codes | ||
const spdlog::string_view_t reset = "\033[m"; | ||
const spdlog::string_view_t bold = "\033[1m"; | ||
const spdlog::string_view_t dark = "\033[2m"; | ||
const spdlog::string_view_t underline = "\033[4m"; | ||
const spdlog::string_view_t blink = "\033[5m"; | ||
const spdlog::string_view_t reverse = "\033[7m"; | ||
const spdlog::string_view_t concealed = "\033[8m"; | ||
const spdlog::string_view_t clear_line = "\033[K"; | ||
|
||
// Foreground colors | ||
const spdlog::string_view_t black = "\033[30m"; | ||
const spdlog::string_view_t red = "\033[31m"; | ||
const spdlog::string_view_t green = "\033[32m"; | ||
const spdlog::string_view_t yellow = "\033[33m"; | ||
const spdlog::string_view_t blue = "\033[34m"; | ||
const spdlog::string_view_t magenta = "\033[35m"; | ||
const spdlog::string_view_t cyan = "\033[36m"; | ||
const spdlog::string_view_t white = "\033[37m"; | ||
|
||
/// Background colors | ||
const spdlog::string_view_t on_black = "\033[40m"; | ||
const spdlog::string_view_t on_red = "\033[41m"; | ||
const spdlog::string_view_t on_green = "\033[42m"; | ||
const spdlog::string_view_t on_yellow = "\033[43m"; | ||
const spdlog::string_view_t on_blue = "\033[44m"; | ||
const spdlog::string_view_t on_magenta = "\033[45m"; | ||
const spdlog::string_view_t on_cyan = "\033[46m"; | ||
const spdlog::string_view_t on_white = "\033[47m"; | ||
|
||
/// Bold colors | ||
const spdlog::string_view_t yellow_bold = "\033[33m\033[1m"; | ||
const spdlog::string_view_t red_bold = "\033[31m\033[1m"; | ||
const spdlog::string_view_t bold_on_red = "\033[1m\033[41m"; | ||
|
||
private: | ||
void print_ccode_(const spdlog::string_view_t &color_code); | ||
void print_range_(const spdlog::memory_buf_t &formatted, size_t start, size_t end); | ||
static std::string to_string(const spdlog::string_view_t &sv); | ||
|
||
FILE *target_file_; | ||
bool should_do_colors_; | ||
std::array<std::string, spdlog::level::n_levels> colors_; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// Copyright (c) 2024, The Endstone Project. (https://endstone.dev) All Rights Reserved. | ||
// | ||
// 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. | ||
|
||
#pragma once | ||
|
||
#include <spdlog/spdlog.h> | ||
|
||
#include "endstone/logger.h" | ||
|
||
class SpdLogAdapter : public Logger { | ||
public: | ||
explicit SpdLogAdapter(std::shared_ptr<spdlog::logger> logger); | ||
void setLevel(Level level) override; | ||
[[nodiscard]] bool isEnabledFor(Level level) const override; | ||
[[nodiscard]] std::string_view getName() const override; | ||
void log(Level level, const std::string &message) const override; | ||
|
||
private: | ||
std::shared_ptr<spdlog::logger> logger_; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
// Copyright (c) 2024, The Endstone Project. (https://endstone.dev) All Rights Reserved. | ||
// | ||
// 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 "endstone_core/spdlog/bedrock_level_formatter.h" | ||
|
||
void BedrockLevelFormatter::format(const spdlog::details::log_msg &msg, const tm &, spdlog::memory_buf_t &dest) | ||
{ | ||
static const std::unordered_map<spdlog::level::level_enum, std::string_view> level_names = { | ||
{spdlog::level::trace, "TRACE"}, {spdlog::level::debug, "DEBUG"}, {spdlog::level::info, "INFO"}, | ||
{spdlog::level::warn, "WARNING"}, {spdlog::level::err, "ERROR"}, {spdlog::level::critical, "CRITICAL"}, | ||
{spdlog::level::off, "OFF"}, | ||
}; | ||
|
||
const auto level_name = level_names.find(msg.level)->second; | ||
const auto *buf_ptr = level_name.data(); | ||
dest.append(buf_ptr, buf_ptr + level_name.size()); | ||
} | ||
|
||
std::unique_ptr<spdlog::custom_flag_formatter> BedrockLevelFormatter::clone() const | ||
{ | ||
return spdlog::details::make_unique<BedrockLevelFormatter>(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
// Copyright (c) 2024, The Endstone Project. (https://endstone.dev) All Rights Reserved. | ||
// | ||
// 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 "endstone_core/spdlog/bedrock_log_sink.h" | ||
|
||
#include <spdlog/pattern_formatter.h> | ||
#include <spdlog/sinks/base_sink-inl.h> | ||
|
||
#include "endstone_core/spdlog/bedrock_level_formatter.h" | ||
|
||
BedrockLogSink::BedrockLogSink(FILE *target_file, spdlog::color_mode mode) | ||
: target_file_(target_file), spdlog::sinks::base_sink<spdlog::details::console_mutex::mutex_t>( | ||
spdlog::details::make_unique<spdlog::pattern_formatter>()) | ||
{ | ||
auto *formatter = dynamic_cast<spdlog::pattern_formatter *>(formatter_.get()); | ||
formatter->add_flag<BedrockLevelFormatter>('L'); | ||
formatter->set_pattern("%^[%Y-%m-%d %H:%M:%S.%e %L] [%n] %v%$"); | ||
// TODO: replace minecraft color format with ansi code | ||
set_color_mode(mode); | ||
colors_.at(spdlog::level::trace) = to_string(white); | ||
colors_.at(spdlog::level::debug) = to_string(cyan); | ||
colors_.at(spdlog::level::info) = to_string(reset); | ||
colors_.at(spdlog::level::warn) = to_string(yellow_bold); | ||
colors_.at(spdlog::level::err) = to_string(red_bold); | ||
colors_.at(spdlog::level::critical) = to_string(bold_on_red); | ||
colors_.at(spdlog::level::off) = to_string(reset); | ||
} | ||
|
||
void BedrockLogSink::set_color_mode(spdlog::color_mode mode) | ||
{ | ||
switch (mode) { | ||
case spdlog::color_mode::always: | ||
should_do_colors_ = true; | ||
return; | ||
case spdlog::color_mode::automatic: | ||
should_do_colors_ = spdlog::details::os::in_terminal(target_file_) && spdlog::details::os::is_color_terminal(); | ||
return; | ||
case spdlog::color_mode::never: | ||
default: | ||
should_do_colors_ = false; | ||
} | ||
} | ||
|
||
std::string BedrockLogSink::to_string(const spdlog::string_view_t &sv) | ||
{ | ||
return {sv.data(), sv.size()}; | ||
} | ||
|
||
void BedrockLogSink::sink_it_(const spdlog::details::log_msg &msg) | ||
{ | ||
msg.color_range_start = 0; | ||
msg.color_range_end = 0; | ||
spdlog::memory_buf_t formatted; | ||
formatter_->format(msg, formatted); | ||
if (should_do_colors_ && msg.color_range_end > msg.color_range_start) { | ||
// before color range | ||
print_range_(formatted, 0, msg.color_range_start); | ||
// in color range | ||
print_ccode_(colors_.at(static_cast<size_t>(msg.level))); | ||
print_range_(formatted, msg.color_range_start, msg.color_range_end); | ||
print_ccode_(reset); | ||
// after color range | ||
print_range_(formatted, msg.color_range_end, formatted.size()); | ||
} | ||
else // no color | ||
{ | ||
print_range_(formatted, 0, formatted.size()); | ||
} | ||
fflush(target_file_); | ||
} | ||
|
||
void BedrockLogSink::flush_() | ||
{ | ||
fflush(target_file_); | ||
} | ||
|
||
void BedrockLogSink::print_ccode_(const spdlog::string_view_t &color_code) | ||
{ | ||
fwrite(color_code.data(), sizeof(char), color_code.size(), target_file_); | ||
} | ||
|
||
void BedrockLogSink::print_range_(const spdlog::memory_buf_t &formatted, size_t start, size_t end) | ||
{ | ||
fwrite(formatted.data() + start, sizeof(char), end - start, target_file_); | ||
} |
Oops, something went wrong.