From 43b0462bb4b4488de52a38cf40404eb53011b5bd Mon Sep 17 00:00:00 2001 From: boddykong <841952496@qq.com> Date: Wed, 25 Nov 2020 17:11:04 +0800 Subject: [PATCH] add udp_skin suport udp log --- example/example.cpp | 15 ++++- include/spdlog/details/udp_client.h | 89 +++++++++++++++++++++++++++++ include/spdlog/sinks/udp_sink.h | 87 ++++++++++++++++++++++++++++ src/spdlog.cpp | 1 + 4 files changed, 191 insertions(+), 1 deletion(-) mode change 100644 => 100755 example/example.cpp create mode 100755 include/spdlog/details/udp_client.h create mode 100755 include/spdlog/sinks/udp_sink.h mode change 100644 => 100755 src/spdlog.cpp diff --git a/example/example.cpp b/example/example.cpp old mode 100644 new mode 100755 index 092eb1af..4172c469 --- a/example/example.cpp +++ b/example/example.cpp @@ -20,6 +20,7 @@ void user_defined_example(); void err_handler_example(); void syslog_example(); void custom_flags_example(); +void udp_example(); #include "spdlog/spdlog.h" #include "spdlog/cfg/env.h" // for loading levels from the environment variable @@ -74,7 +75,7 @@ int main(int, char *[]) trace_example(); stopwatch_example(); custom_flags_example(); - + udp_example(); // Flush all *registered* loggers using a worker thread every 3 seconds. // note: registered loggers *must* be thread safe for this to work correctly! spdlog::flush_every(std::chrono::seconds(3)); @@ -197,6 +198,7 @@ void trace_example() // stopwatch example #include "spdlog/stopwatch.h" #include +#include void stopwatch_example() { spdlog::stopwatch sw; @@ -292,3 +294,14 @@ void custom_flags_example() formatter->add_flag('*').set_pattern("[%n] [%*] [%^%l%$] %v"); spdlog::set_formatter(std::move(formatter)); } + +void udp_example() +{ + // using spdlog::details::make_unique; + //auto daily_logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30); + spdlog::sinks::udp_sink_config cfg("127.0.0.1", 11091); + auto my_logger = spdlog::udp_logger_mt("udplog", cfg); + my_logger->set_level(spdlog::level::debug); + my_logger->info("hello world"); + my_logger->info("are you ok"); +} diff --git a/include/spdlog/details/udp_client.h b/include/spdlog/details/udp_client.h new file mode 100755 index 00000000..11ba8888 --- /dev/null +++ b/include/spdlog/details/udp_client.h @@ -0,0 +1,89 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifdef _WIN32 +#error include tcp_client-windows.h instead +#endif + +// tcp client helper +#include +#include + +#include +#include +#include +#include +#include + +#include + +namespace spdlog { +namespace details { +class udp_client +{ + int socket_ = -1; + std::string m_svrIp; + int m_svrPort; + struct sockaddr_in sockAddr_; +public: + + bool init(const std::string &host, int port) + { + m_svrIp = host; + m_svrPort = port; + + socket_ = socket(PF_INET, SOCK_DGRAM, 0); + if (socket_ < 0) + { + throw_spdlog_ex("error: Create Socket Failed!"); + return false; + } + + sockAddr_.sin_family = AF_INET; + sockAddr_.sin_port = htons(m_svrPort); + inet_aton(m_svrIp.c_str(), &sockAddr_.sin_addr); + + memset(sockAddr_.sin_zero, 0x00, 8); + return true; + } + + bool is_init() const + { + return socket_ != -1; + } + + void close() + { + if (is_init()) + { + ::close(socket_); + socket_ = -1; + } + } + + int fd() const + { + return socket_; + } + + ~udp_client() + { + close(); + } + + // Send exactly n_bytes of the given data. + // On error close the connection and throw. + void send(const char *data, size_t n_bytes) + { + size_t toslen = 0; + size_t tolen = sizeof(struct sockaddr); + if (( toslen = sendto(socket_, data, n_bytes, 0, (struct sockaddr *)&sockAddr_, tolen)) == -1) + { + throw_spdlog_ex("write(2) failed", errno); + } + } +}; +} // namespace details +} // namespace spdlog diff --git a/include/spdlog/sinks/udp_sink.h b/include/spdlog/sinks/udp_sink.h new file mode 100755 index 00000000..767221a3 --- /dev/null +++ b/include/spdlog/sinks/udp_sink.h @@ -0,0 +1,87 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include +#include +#ifdef _WIN32 +#include +#else +#include +#endif + +#include +#include +#include +#include + +#pragma once + +// Simple tcp client sink +// Connects to remote address and send the formatted log. +// Will attempt to reconnect if connection drops. +// If more complicated behaviour is needed (i.e get responses), you can inherit it and override the sink_it_ method. + +namespace spdlog { +namespace sinks { + +struct udp_sink_config +{ + std::string server_host; + int server_port; + + udp_sink_config(std::string host, int port) + : server_host{std::move(host)} + , server_port{port} + {} +}; + +template +class udp_sink : public spdlog::sinks::base_sink +{ +public: + // connect to tcp host/port or throw if failed + // host can be hostname or ip address + + explicit udp_sink(udp_sink_config sink_config) + : config_{std::move(sink_config)} + { + + } + + ~udp_sink() override = default; + +protected: + void sink_it_(const spdlog::details::log_msg &msg) override + { + spdlog::memory_buf_t formatted; + spdlog::sinks::base_sink::formatter_->format(msg, formatted); + if (!client_.is_init()) + { + client_.init(config_.server_host, config_.server_port); + } + client_.send(formatted.data(), formatted.size()); + } + + void flush_() override {} + udp_sink_config config_; + details::udp_client client_; +}; + +using udp_sink_mt = udp_sink; +using udp_sink_st = udp_sink; + +} // namespace sinks + +// +// factory functions +// +template +inline std::shared_ptr udp_logger_mt(const std::string &logger_name, sinks::udp_sink_config skin_config) +{ + return Factory::template create(logger_name, skin_config); +} + +} // namespace spdlog diff --git a/src/spdlog.cpp b/src/spdlog.cpp old mode 100644 new mode 100755 index c0904e6c..c7970372 --- a/src/spdlog.cpp +++ b/src/spdlog.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include