12#include <boost/lexical_cast.hpp>
25 return boost::asio::ip::udp::endpoint(boost::asio::ip::address_v4(e.
get_address()), e.
port() );
55 mvo.
erase(
"endpoint");
56 cfg.
host = mvo[
"host"].as<std::string>();
60 for(
auto&& field_name : config::reserved_field_names) {
63 (
"field_name", field_name));
67 if (!std::regex_match(
field.key(), config::user_field_name_pattern)) {
68 FC_THROW_EXCEPTION(invalid_arg_exception,
"Field name '${field_name} must begin with an underscore and contain only letters, numbers, underscores, dashes, and dots.",
69 (
"field_name",
field.key()));
96 if (!my->gelf_endpoint)
100 string::size_type colon_pos = my->cfg.endpoint.find(
':');
103 uint16_t port = boost::lexical_cast<uint16_t>(my->cfg.endpoint.substr(colon_pos + 1, my->cfg.endpoint.size()));
105 string hostname = my->cfg.endpoint.substr( 0, colon_pos );
106 auto endpoints =
resolve(io_service, hostname, port);
107 if (endpoints.empty())
108 FC_THROW_EXCEPTION(unknown_host_exception,
"The logging destination host name can not be resolved: ${hostname}",
109 (
"hostname", hostname));
110 my->gelf_endpoint = endpoints.back();
112 catch (
const boost::bad_lexical_cast&)
114 FC_THROW(
"Bad port: ${port}", (
"port", my->cfg.endpoint.substr(colon_pos + 1, my->cfg.endpoint.size())));
118 if (my->gelf_endpoint)
120 my->gelf_socket.initialize(io_service);
121 my->gelf_socket.open();
122 std::cerr <<
"opened GELF socket to endpoint " << my->cfg.endpoint <<
"\n";
127 std::cerr <<
"error opening GELF socket to endpoint " << my->cfg.endpoint <<
"\n";
136 if (!my->gelf_endpoint)
142 gelf_message[
"version"] =
"1.1";
143 gelf_message[
"host"] = my->cfg.host;
144 gelf_message[
"short_message"] =
format_string(message.get_format(), message.get_data(),
true);
148 gelf_message[
"timestamp"] = time_ns / 1000000.;
149 gelf_message[
"_timestamp_ns"] = time_ns;
154 switch (
context.get_log_level())
157 gelf_message[
"level"] = 7;
160 gelf_message[
"level"] = 6;
163 gelf_message[
"level"] = 4;
166 gelf_message[
"level"] = 3;
171 gelf_message[
"level"] = 6;
175 if (!
context.get_context().empty())
176 gelf_message[
"context"] =
context.get_context();
177 gelf_message[
"_line"] =
context.get_line_number();
178 gelf_message[
"_file"] =
context.get_file();
179 gelf_message[
"_method_name"] =
context.get_method();
180 gelf_message[
"_thread_name"] =
context.get_thread_name();
181 if (!
context.get_task_name().empty())
182 gelf_message[
"_task_name"] =
context.get_task_name();
184 for(
auto&&
field : my->cfg.user_fields) {
191 gelf_message_as_string =
zlib_compress(gelf_message_as_string);
199 const unsigned max_payload_size = 512;
201 if (gelf_message_as_string.size() <= max_payload_size)
204 std::shared_ptr<char> send_buffer(
new char[gelf_message_as_string.size()],
205 [](
char*
p){ delete[] p; });
206 memcpy(send_buffer.get(), gelf_message_as_string.c_str(),
207 gelf_message_as_string.size());
209 my->gelf_socket.send_to(send_buffer, gelf_message_as_string.size(),
217 uint64_t message_id =
city_hash64(gelf_message_as_string.c_str(), gelf_message_as_string.size());
218 const unsigned header_length = 2 + 8 + 1 + 1 ;
219 const unsigned body_length = max_payload_size - header_length;
220 unsigned total_number_of_packets = (gelf_message_as_string.size() + body_length - 1) / body_length;
221 unsigned bytes_sent = 0;
222 unsigned number_of_packets_sent = 0;
223 while (bytes_sent < gelf_message_as_string.size())
225 unsigned bytes_to_send = std::min((
unsigned)gelf_message_as_string.size() - bytes_sent,
228 std::shared_ptr<char> send_buffer(
new char[max_payload_size],
229 [](
char*
p){
delete[]
p; });
230 char*
ptr = send_buffer.get();
232 *(
unsigned char*)
ptr++ = 0x1e;
233 *(
unsigned char*)
ptr++ = 0x0f;
236 memcpy(
ptr, (
char*)&message_id,
sizeof(message_id));
237 ptr +=
sizeof(message_id);
239 *(
unsigned char*)(
ptr++) = number_of_packets_sent;
240 *(
unsigned char*)(
ptr++) = total_number_of_packets;
241 memcpy(
ptr, gelf_message_as_string.c_str() + bytes_sent,
243 my->gelf_socket.send_to(send_buffer, header_length + bytes_to_send,
245 ++number_of_packets_sent;
246 bytes_sent += bytes_to_send;
248 FC_ASSERT(number_of_packets_sent == total_number_of_packets);
std::shared_ptr< appender > ptr
static constexpr fc::microseconds format_time_limit
std::optional< boost::asio::ip::udp::endpoint > gelf_endpoint
virtual void log(const log_message &m) override
gelf_appender(const variant &args)
void initialize(boost::asio::io_service &io_service) override
Required for name resolution and socket initialization.
const address & get_address() const
static endpoint from_string(const string &s)
static string to_string(const variant &v, const yield_function_t &yield, const output_formatting format=output_formatting::stringify_large_ints_and_doubles)
provides information about where and when a log message was generated.
aggregates a message along with the context and associated meta-information.
constexpr int64_t count() const
An order-preserving dictionary of variants.
void erase(const string &key)
constexpr const microseconds & time_since_epoch() const
bool contains(const char *key) const
stores null, int64, uint64, double, bool, string, std::vector<variant>, and variant_object's.
Defines exception's used by fc.
#define FC_THROW_EXCEPTION(EXCEPTION, FORMAT,...)
#define FC_ASSERT(TEST,...)
Checks a condition and throws an assert_exception if the test is FALSE.
boost::asio::ip::udp::endpoint to_asio_ep(const fc::ip::endpoint &e)
fc::string to_string(double)
string zlib_compress(const string &in)
uint64_t city_hash64(const char *buf, size_t len)
std::vector< boost::asio::ip::udp::endpoint > resolve(boost::asio::io_service &io_service, const std::string &host, uint16_t port)
void from_variant(const fc::variant &v, sysio::chain::chain_id_type &cid)
fc::string format_string(const fc::string &, const variant_object &, bool minimize=false)
unsigned __int64 uint64_t
variant_object user_fields
static const std::regex user_field_name_pattern
static const std::vector< std::string > reserved_field_names
memcpy((char *) pInfo->slotDescription, s, l)