mirror of
https://git.wownero.com/wownero/wownero.git
synced 2024-08-15 01:03:23 +00:00
This replaces the epee and data_loggers logging systems with a single one, and also adds filename:line and explicit severity levels. Categories may be defined, and logging severity set by category (or set of categories). epee style 0-4 log level maps to a sensible severity configuration. Log files now also rotate when reaching 100 MB. To select which logs to output, use the MONERO_LOGS environment variable, with a comma separated list of categories (globs are supported), with their requested severity level after a colon. If a log matches more than one such setting, the last one in the configuration string applies. A few examples: This one is (mostly) silent, only outputting fatal errors: MONERO_LOGS=*:FATAL This one is very verbose: MONERO_LOGS=*:TRACE This one is totally silent (logwise): MONERO_LOGS="" This one outputs all errors and warnings, except for the "verify" category, which prints just fatal errors (the verify category is used for logs about incoming transactions and blocks, and it is expected that some/many will fail to verify, hence we don't want the spam): MONERO_LOGS=*:WARNING,verify:FATAL Log levels are, in decreasing order of priority: FATAL, ERROR, WARNING, INFO, DEBUG, TRACE Subcategories may be added using prefixes and globs. This example will output net.p2p logs at the TRACE level, but all other net* logs only at INFO: MONERO_LOGS=*:ERROR,net*:INFO,net.p2p:TRACE Logs which are intended for the user (which Monero was using a lot through epee, but really isn't a nice way to go things) should use the "global" category. There are a few helper macros for using this category, eg: MGINFO("this shows up by default") or MGINFO_RED("this is red"), to try to keep a similar look and feel for now. Existing epee log macros still exist, and map to the new log levels, but since they're used as a "user facing" UI element as much as a logging system, they often don't map well to log severities (ie, a log level 0 log may be an error, or may be something we want the user to see, such as an important info). In those cases, I tried to use the new macros. In other cases, I left the existing macros in. When modifying logs, it is probably best to switch to the new macros with explicit levels. The --log-level options and set_log commands now also accept category settings, in addition to the epee style log levels.
380 lines
15 KiB
C++
380 lines
15 KiB
C++
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
// All rights reserved.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are met:
|
|
// * Redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
// * Redistributions in binary form must reproduce the above copyright
|
|
// notice, this list of conditions and the following disclaimer in the
|
|
// documentation and/or other materials provided with the distribution.
|
|
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
// names of its contributors may be used to endorse or promote products
|
|
// derived from this software without specific prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
//
|
|
|
|
#pragma once
|
|
#include "parserse_base_utils.h"
|
|
#include "file_io_utils.h"
|
|
|
|
namespace epee
|
|
{
|
|
using namespace misc_utils::parse;
|
|
namespace serialization
|
|
{
|
|
namespace json
|
|
{
|
|
#define CHECK_ISSPACE() if(!isspace(*it)){ ASSERT_MES_AND_THROW("Wrong JSON character at: " << std::string(it, buf_end));}
|
|
|
|
/*inline void parse_error()
|
|
{
|
|
ASSERT_MES_AND_THROW("json parse error");
|
|
}*/
|
|
template<class t_storage>
|
|
inline void run_handler(typename t_storage::hsection current_section, std::string::const_iterator& sec_buf_begin, std::string::const_iterator buf_end, t_storage& stg)
|
|
{
|
|
|
|
std::string::const_iterator sub_element_start;
|
|
std::string name;
|
|
typename t_storage::harray h_array = nullptr;
|
|
enum match_state
|
|
{
|
|
match_state_lookup_for_section_start,
|
|
match_state_lookup_for_name,
|
|
match_state_waiting_separator,
|
|
match_state_wonder_after_separator,
|
|
match_state_wonder_after_value,
|
|
match_state_wonder_array,
|
|
match_state_array_after_value,
|
|
match_state_array_waiting_value,
|
|
match_state_error
|
|
};
|
|
|
|
enum array_mode
|
|
{
|
|
array_mode_undifined = 0,
|
|
array_mode_sections,
|
|
array_mode_string,
|
|
array_mode_numbers,
|
|
array_mode_booleans
|
|
};
|
|
|
|
match_state state = match_state_lookup_for_section_start;
|
|
array_mode array_md = array_mode_undifined;
|
|
std::string::const_iterator it = sec_buf_begin;
|
|
for(;it != buf_end;it++)
|
|
{
|
|
switch (state)
|
|
{
|
|
case match_state_lookup_for_section_start:
|
|
if(*it == '{')
|
|
state = match_state_lookup_for_name;
|
|
else CHECK_ISSPACE();
|
|
break;
|
|
case match_state_lookup_for_name:
|
|
switch(*it)
|
|
{
|
|
case '"':
|
|
match_string2(it, buf_end, name);
|
|
state = match_state_waiting_separator;
|
|
break;
|
|
case '}':
|
|
//this is it! section ends here.
|
|
//seems that it is empty section
|
|
sec_buf_begin = it;
|
|
return;
|
|
default:
|
|
CHECK_ISSPACE();
|
|
}
|
|
break;
|
|
case match_state_waiting_separator:
|
|
if(*it == ':')
|
|
state = match_state_wonder_after_separator;
|
|
else CHECK_ISSPACE();
|
|
break;
|
|
case match_state_wonder_after_separator:
|
|
if(*it == '"')
|
|
{//just a named string value started
|
|
std::string val;
|
|
match_string2(it, buf_end, val);
|
|
//insert text value
|
|
stg.set_value(name, val, current_section);
|
|
state = match_state_wonder_after_value;
|
|
}else if (isdigit(*it) || *it == '-')
|
|
{//just a named number value started
|
|
std::string val;
|
|
bool is_v_float = false;bool is_signed = false;
|
|
match_number2(it, buf_end, val, is_v_float, is_signed);
|
|
if(!is_v_float)
|
|
{
|
|
if(is_signed)
|
|
{
|
|
int64_t nval = boost::lexical_cast<int64_t>(val);
|
|
stg.set_value(name, nval, current_section);
|
|
}else
|
|
{
|
|
uint64_t nval = boost::lexical_cast<uint64_t >(val);
|
|
stg.set_value(name, nval, current_section);
|
|
}
|
|
}else
|
|
{
|
|
double nval = boost::lexical_cast<double>(val);
|
|
stg.set_value(name, nval, current_section);
|
|
}
|
|
state = match_state_wonder_after_value;
|
|
}else if(isalpha(*it) )
|
|
{// could be null, true or false
|
|
std::string word;
|
|
match_word2(it, buf_end, word);
|
|
if(boost::iequals(word, "null"))
|
|
{
|
|
state = match_state_wonder_after_value;
|
|
//just skip this,
|
|
}else if(boost::iequals(word, "true"))
|
|
{
|
|
stg.set_value(name, true, current_section);
|
|
state = match_state_wonder_after_value;
|
|
}else if(boost::iequals(word, "false"))
|
|
{
|
|
stg.set_value(name, false, current_section);
|
|
state = match_state_wonder_after_value;
|
|
}else ASSERT_MES_AND_THROW("Unknown value keyword " << word);
|
|
}else if(*it == '{')
|
|
{
|
|
//sub section here
|
|
typename t_storage::hsection new_sec = stg.open_section(name, current_section, true);
|
|
CHECK_AND_ASSERT_THROW_MES(new_sec, "Failed to insert new section in json: " << std::string(it, buf_end));
|
|
run_handler(new_sec, it, buf_end, stg);
|
|
state = match_state_wonder_after_value;
|
|
}else if(*it == '[')
|
|
{//array of something
|
|
state = match_state_wonder_array;
|
|
}else CHECK_ISSPACE();
|
|
break;
|
|
case match_state_wonder_after_value:
|
|
if(*it == ',')
|
|
state = match_state_lookup_for_name;
|
|
else if(*it == '}')
|
|
{
|
|
//this is it! section ends here.
|
|
sec_buf_begin = it;
|
|
return;
|
|
}else CHECK_ISSPACE();
|
|
break;
|
|
case match_state_wonder_array:
|
|
if(*it == '[')
|
|
{
|
|
ASSERT_MES_AND_THROW("array of array not suppoerted yet :( sorry");
|
|
//mean array of array
|
|
}
|
|
if(*it == '{')
|
|
{
|
|
//mean array of sections
|
|
typename t_storage::hsection new_sec = nullptr;
|
|
h_array = stg.insert_first_section(name, new_sec, current_section);
|
|
CHECK_AND_ASSERT_THROW_MES(h_array&&new_sec, "failed to create new section");
|
|
run_handler(new_sec, it, buf_end, stg);
|
|
state = match_state_array_after_value;
|
|
array_md = array_mode_sections;
|
|
}else if(*it == '"')
|
|
{
|
|
//mean array of strings
|
|
std::string val;
|
|
match_string2(it, buf_end, val);
|
|
h_array = stg.insert_first_value(name, val, current_section);
|
|
CHECK_AND_ASSERT_THROW_MES(h_array, " failed to insert values entry");
|
|
state = match_state_array_after_value;
|
|
array_md = array_mode_string;
|
|
}else if (isdigit(*it) || *it == '-')
|
|
{//array of numbers value started
|
|
std::string val;
|
|
bool is_v_float = false;bool is_signed_val = false;
|
|
match_number2(it, buf_end, val, is_v_float, is_signed_val);
|
|
if(!is_v_float)
|
|
{
|
|
int64_t nval = boost::lexical_cast<int64_t>(val);//bool res = string_tools::string_to_num_fast(val, nval);
|
|
h_array = stg.insert_first_value(name, nval, current_section);
|
|
CHECK_AND_ASSERT_THROW_MES(h_array, " failed to insert values section entry");
|
|
}else
|
|
{
|
|
double nval = boost::lexical_cast<double>(val);//bool res = string_tools::string_to_num_fast(val, nval);
|
|
h_array = stg.insert_first_value(name, nval, current_section);
|
|
CHECK_AND_ASSERT_THROW_MES(h_array, " failed to insert values section entry");
|
|
}
|
|
|
|
state = match_state_array_after_value;
|
|
array_md = array_mode_numbers;
|
|
}else if(*it == ']')//empty array
|
|
{
|
|
array_md = array_mode_undifined;
|
|
state = match_state_wonder_after_value;
|
|
}else if(isalpha(*it) )
|
|
{// array of booleans
|
|
std::string word;
|
|
match_word2(it, buf_end, word);
|
|
if(boost::iequals(word, "true"))
|
|
{
|
|
h_array = stg.insert_first_value(name, true, current_section);
|
|
CHECK_AND_ASSERT_THROW_MES(h_array, " failed to insert values section entry");
|
|
state = match_state_array_after_value;
|
|
array_md = array_mode_booleans;
|
|
}else if(boost::iequals(word, "false"))
|
|
{
|
|
h_array = stg.insert_first_value(name, false, current_section);
|
|
CHECK_AND_ASSERT_THROW_MES(h_array, " failed to insert values section entry");
|
|
state = match_state_array_after_value;
|
|
array_md = array_mode_booleans;
|
|
|
|
}else ASSERT_MES_AND_THROW("Unknown value keyword " << word)
|
|
}else CHECK_ISSPACE();
|
|
break;
|
|
case match_state_array_after_value:
|
|
if(*it == ',')
|
|
state = match_state_array_waiting_value;
|
|
else if(*it == ']')
|
|
{
|
|
h_array = nullptr;
|
|
array_md = array_mode_undifined;
|
|
state = match_state_wonder_after_value;
|
|
}else CHECK_ISSPACE();
|
|
break;
|
|
case match_state_array_waiting_value:
|
|
switch(array_md)
|
|
{
|
|
case array_mode_sections:
|
|
if(*it == '{')
|
|
{
|
|
typename t_storage::hsection new_sec = NULL;
|
|
bool res = stg.insert_next_section(h_array, new_sec);
|
|
CHECK_AND_ASSERT_THROW_MES(res&&new_sec, "failed to insert next section");
|
|
run_handler(new_sec, it, buf_end, stg);
|
|
state = match_state_array_after_value;
|
|
}else CHECK_ISSPACE();
|
|
break;
|
|
case array_mode_string:
|
|
if(*it == '"')
|
|
{
|
|
std::string val;
|
|
match_string2(it, buf_end, val);
|
|
bool res = stg.insert_next_value(h_array, val);
|
|
CHECK_AND_ASSERT_THROW_MES(res, "failed to insert values");
|
|
state = match_state_array_after_value;
|
|
}else CHECK_ISSPACE();
|
|
break;
|
|
case array_mode_numbers:
|
|
if (isdigit(*it) || *it == '-')
|
|
{//array of numbers value started
|
|
std::string val;
|
|
bool is_v_float = false;bool is_signed_val = false;
|
|
match_number2(it, buf_end, val, is_v_float, is_signed_val);
|
|
bool insert_res = false;
|
|
if(!is_v_float)
|
|
{
|
|
int64_t nval = boost::lexical_cast<int64_t>(val); //bool res = string_tools::string_to_num_fast(val, nval);
|
|
insert_res = stg.insert_next_value(h_array, nval);
|
|
|
|
}else
|
|
{
|
|
//TODO: optimize here if need
|
|
double nval = boost::lexical_cast<double>(val); //string_tools::string_to_num_fast(val, nval);
|
|
insert_res = stg.insert_next_value(h_array, nval);
|
|
}
|
|
CHECK_AND_ASSERT_THROW_MES(insert_res, "Failed to insert next value");
|
|
state = match_state_array_after_value;
|
|
array_md = array_mode_numbers;
|
|
}else CHECK_ISSPACE();
|
|
break;
|
|
case array_mode_booleans:
|
|
if(isalpha(*it) )
|
|
{// array of booleans
|
|
std::string word;
|
|
match_word2(it, buf_end, word);
|
|
if(boost::iequals(word, "true"))
|
|
{
|
|
bool r = stg.insert_next_value(h_array, true);
|
|
CHECK_AND_ASSERT_THROW_MES(r, " failed to insert values section entry");
|
|
state = match_state_array_after_value;
|
|
}else if(boost::iequals(word, "false"))
|
|
{
|
|
bool r = stg.insert_next_value(h_array, false);
|
|
CHECK_AND_ASSERT_THROW_MES(r, " failed to insert values section entry");
|
|
state = match_state_array_after_value;
|
|
}
|
|
else ASSERT_MES_AND_THROW("Unknown value keyword " << word);
|
|
}else CHECK_ISSPACE();
|
|
break;
|
|
case array_mode_undifined:
|
|
default:
|
|
ASSERT_MES_AND_THROW("Bad array state");
|
|
}
|
|
break;
|
|
case match_state_error:
|
|
default:
|
|
ASSERT_MES_AND_THROW("WRONG JSON STATE");
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
{
|
|
"firstName": "John",
|
|
"lastName": "Smith",
|
|
"age": 25,
|
|
"address": {
|
|
"streetAddress": "21 2nd Street",
|
|
"city": "New York",
|
|
"state": "NY",
|
|
"postalCode": -10021,
|
|
"have_boobs": true,
|
|
"have_balls": false
|
|
},
|
|
"phoneNumber": [
|
|
{
|
|
"type": "home",
|
|
"number": "212 555-1234"
|
|
},
|
|
{
|
|
"type": "fax",
|
|
"number": "646 555-4567"
|
|
}
|
|
],
|
|
"phoneNumbers": [
|
|
"812 123-1234",
|
|
"916 123-4567"
|
|
]
|
|
}
|
|
*/
|
|
template<class t_storage>
|
|
inline bool load_from_json(const std::string& buff_json, t_storage& stg)
|
|
{
|
|
std::string::const_iterator sec_buf_begin = buff_json.begin();
|
|
try
|
|
{
|
|
run_handler(nullptr, sec_buf_begin, buff_json.end(), stg);
|
|
return true;
|
|
}
|
|
catch(const std::exception& ex)
|
|
{
|
|
MERROR("Failed to parse json, what: " << ex.what());
|
|
return false;
|
|
}
|
|
catch(...)
|
|
{
|
|
MERROR("Failed to parse json");
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|