mirror of https://github.com/pvnis/srsRAN_4G.git
Import latest srslog version (#1796)
* - Import latest srslog version. - Adjusted the nas_test to create logs correctly. - Remove timestamp formatting now that is provided by srslog.master
parent
924cc4f937
commit
51b27fc255
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,2 +1,2 @@
|
|||||||
#include "os.h"
|
#include "os.h"
|
||||||
#warning "fmt/posix.h is deprecated; use fmt/os.h instead"
|
#warning "fmt/posix.h is deprecated; use fmt/os.h instead"
|
||||||
|
@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013-2020 Software Radio Systems Limited
|
||||||
|
*
|
||||||
|
* This file is part of srsLTE.
|
||||||
|
*
|
||||||
|
* srsLTE is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* srsLTE is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* A copy of the GNU Affero General Public License can be found in
|
||||||
|
* the LICENSE file in the top-level directory of this distribution
|
||||||
|
* and at http://www.gnu.org/licenses/.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SRSLOG_EVENT_TRACE_H
|
||||||
|
#define SRSLOG_EVENT_TRACE_H
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace srslog {
|
||||||
|
|
||||||
|
class log_channel;
|
||||||
|
|
||||||
|
/// The event tracing framework allows to trace any kind of event inside an
|
||||||
|
/// application.
|
||||||
|
/// To enable event tracing the ENABLE_SRSLOG_EVENT_TRACE macro symbol should
|
||||||
|
/// be defined, otherwise calls to the tracing framework will be ignored. This
|
||||||
|
/// is important to avoid the overhead of tracing when it is not required.
|
||||||
|
/// For details about each event trace type please refer to:
|
||||||
|
/// https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/edit
|
||||||
|
|
||||||
|
/// Initializes the event trace framework saving the trace events to a
|
||||||
|
/// "event_trace.log" file.
|
||||||
|
void event_trace_init();
|
||||||
|
|
||||||
|
/// Initializes the event trace framework using the specified log channel to log
|
||||||
|
/// all trace events.
|
||||||
|
void event_trace_init(log_channel& c);
|
||||||
|
|
||||||
|
#ifdef ENABLE_SRSLOG_EVENT_TRACE
|
||||||
|
|
||||||
|
/// Generates the begin phase of a duration event.
|
||||||
|
void trace_duration_begin(const std::string& category, const std::string& name);
|
||||||
|
|
||||||
|
/// Generates the end phase of a duration event.
|
||||||
|
void trace_duration_end(const std::string& category, const std::string& name);
|
||||||
|
|
||||||
|
/// Generates a complete event.
|
||||||
|
#define trace_complete_event(C, N) \
|
||||||
|
auto scoped_complete_event_variable = detail::scoped_complete_event(C, N)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/// No-ops.
|
||||||
|
#define trace_duration_begin(C, N)
|
||||||
|
#define trace_duration_end(C, N)
|
||||||
|
#define trace_complete_event(C, N)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
/// Scoped type object for implementing a complete event.
|
||||||
|
class scoped_complete_event
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
scoped_complete_event(std::string cat, std::string n) :
|
||||||
|
category(std::move(cat)),
|
||||||
|
name(std::move(n)),
|
||||||
|
start(std::chrono::steady_clock::now())
|
||||||
|
{}
|
||||||
|
|
||||||
|
~scoped_complete_event();
|
||||||
|
|
||||||
|
private:
|
||||||
|
const std::string category;
|
||||||
|
const std::string name;
|
||||||
|
std::chrono::time_point<std::chrono::steady_clock> start;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
} // namespace srslog
|
||||||
|
|
||||||
|
#endif // SRSLOG_EVENT_TRACE_H
|
@ -0,0 +1,168 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013-2020 Software Radio Systems Limited
|
||||||
|
*
|
||||||
|
* This file is part of srsLTE.
|
||||||
|
*
|
||||||
|
* srsLTE is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* srsLTE is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* A copy of the GNU Affero General Public License can be found in
|
||||||
|
* the LICENSE file in the top-level directory of this distribution
|
||||||
|
* and at http://www.gnu.org/licenses/.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SRSLOG_SRSLOG_C_H
|
||||||
|
#define SRSLOG_SRSLOG_C_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#include <cstddef>
|
||||||
|
#else
|
||||||
|
#include <stddef.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Common types.
|
||||||
|
*/
|
||||||
|
typedef int srslog_bool;
|
||||||
|
typedef struct srslog_opaque_sink srslog_sink;
|
||||||
|
typedef struct srslog_opaque_log_channel srslog_log_channel;
|
||||||
|
typedef struct srslog_opaque_basic_logger srslog_logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function initializes the logging framework. It must be called before
|
||||||
|
* any log entry is generated.
|
||||||
|
* NOTE: Calling this function more than once has no side effects.
|
||||||
|
*/
|
||||||
|
void srslog_init(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Installs the specified sink to be used as the default one by new log
|
||||||
|
* channels and loggers.
|
||||||
|
* The initial default sink writes to stdout.
|
||||||
|
*/
|
||||||
|
void srslog_set_default_sink(srslog_sink* s);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the instance of the default sink being used.
|
||||||
|
*/
|
||||||
|
srslog_sink* srslog_get_default_sink(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an instance of a log_channel with the specified id that writes to
|
||||||
|
* the default sink using the default log channel configuration.
|
||||||
|
* NOTE: Any '#' characters in the id will get removed.
|
||||||
|
*/
|
||||||
|
srslog_log_channel* srslog_fetch_log_channel(const char* id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a log channel with the specified id string in the repository. On
|
||||||
|
* success returns a pointer to the requested log channel, otherwise NULL.
|
||||||
|
*/
|
||||||
|
srslog_log_channel* srslog_find_log_channel(const char* id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controls whether the specified channel accepts incoming log entries.
|
||||||
|
*/
|
||||||
|
void srslog_set_log_channel_enabled(srslog_log_channel* channel,
|
||||||
|
srslog_bool enabled);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns 1 if the specified channel is accepting incoming log entries,
|
||||||
|
* otherwise 0.
|
||||||
|
*/
|
||||||
|
srslog_bool srslog_is_log_channel_enabled(srslog_log_channel* channel);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the id string of the specified channel.
|
||||||
|
*/
|
||||||
|
const char* srslog_get_log_channel_id(srslog_log_channel* channel);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs the provided log entry using the specified log channel. When the channel
|
||||||
|
* is disabled the log entry wil be discarded.
|
||||||
|
* NOTE: Only printf style formatting is supported when using the C API.
|
||||||
|
*/
|
||||||
|
void srslog_log(srslog_log_channel* channel, const char* fmt, ...);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an instance of a basic logger (see basic_logger type) with the
|
||||||
|
* specified id string. All logger channels will write into the default sink.
|
||||||
|
*/
|
||||||
|
srslog_logger* srslog_fetch_default_logger(const char* id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a logger with the specified id string in the repository. On success
|
||||||
|
* returns a pointer to the requested log channel, otherwise NULL.
|
||||||
|
*/
|
||||||
|
srslog_logger* srslog_find_default_logger(const char* id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These functions log the provided log entry using the specified logger.
|
||||||
|
* Entries are automatically discarded depending on the configured level of the
|
||||||
|
* logger.
|
||||||
|
* NOTE: Only printf style formatting is supported when using the C API.
|
||||||
|
*/
|
||||||
|
void srslog_debug(srslog_logger* log, const char* fmt, ...);
|
||||||
|
void srslog_info(srslog_logger* log, const char* fmt, ...);
|
||||||
|
void srslog_warning(srslog_logger* log, const char* fmt, ...);
|
||||||
|
void srslog_error(srslog_logger* log, const char* fmt, ...);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the id string of the specified logger.
|
||||||
|
*/
|
||||||
|
const char* srslog_get_logger_id(srslog_logger* log);
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
srslog_lvl_error, /**< error logging level */
|
||||||
|
srslog_lvl_warning, /**< warning logging level */
|
||||||
|
srslog_lvl_info, /**< info logging level */
|
||||||
|
srslog_lvl_debug /**< debug logging level */
|
||||||
|
} srslog_log_levels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the logging level into the specified logger.
|
||||||
|
*/
|
||||||
|
void srslog_set_logger_level(srslog_logger* log, srslog_log_levels lvl);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a sink with the specified id string in the repository. On
|
||||||
|
* success returns a pointer to the requested sink, otherwise NULL.
|
||||||
|
*/
|
||||||
|
srslog_sink* srslog_find_sink(const char* id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an instance of a sink that writes to the stdout stream.
|
||||||
|
*/
|
||||||
|
srslog_sink* srslog_fetch_stdout_sink(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an instance of a sink that writes to the stderr stream.
|
||||||
|
*/
|
||||||
|
srslog_sink* srslog_fetch_stderr_sink(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an instance of a sink that writes into a file in the specified path.
|
||||||
|
* Specifying a max_size value different to zero will make the sink create a
|
||||||
|
* new file each time the current file exceeds this value. The units of
|
||||||
|
* max_size are bytes.
|
||||||
|
* NOTE: Any '#' characters in the id will get removed.
|
||||||
|
*/
|
||||||
|
srslog_sink* srslog_fetch_file_sink(const char* path, size_t max_size);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013-2020 Software Radio Systems Limited
|
||||||
|
*
|
||||||
|
* This file is part of srsLTE.
|
||||||
|
*
|
||||||
|
* srsLTE is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* srsLTE is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* A copy of the GNU Affero General Public License can be found in
|
||||||
|
* the LICENSE file in the top-level directory of this distribution
|
||||||
|
* and at http://www.gnu.org/licenses/.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "srslte/srslog/event_trace.h"
|
||||||
|
#include "srslte/srslog/srslog.h"
|
||||||
|
#include <cassert>
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
|
#undef trace_duration_begin
|
||||||
|
#undef trace_duration_end
|
||||||
|
#undef trace_complete_event
|
||||||
|
|
||||||
|
using namespace srslog;
|
||||||
|
|
||||||
|
/// Log channel where event traces will get sent.
|
||||||
|
static log_channel* tracer = nullptr;
|
||||||
|
|
||||||
|
void srslog::event_trace_init()
|
||||||
|
{
|
||||||
|
// Nothing to do if the user previously set a custom channel or this is not
|
||||||
|
// the first time this function is called.
|
||||||
|
if (tracer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default file name where event traces will get stored.
|
||||||
|
static constexpr char default_file_name[] = "event_trace.log";
|
||||||
|
|
||||||
|
// Create the default event trace channel.
|
||||||
|
//:TODO: handle name reservation.
|
||||||
|
sink* s = create_file_sink(default_file_name);
|
||||||
|
assert(s && "Default event file sink is reserved");
|
||||||
|
tracer = create_log_channel("event_trace_channel", *s);
|
||||||
|
assert(tracer && "Default event trace channel is reserved");
|
||||||
|
}
|
||||||
|
|
||||||
|
void srslog::event_trace_init(log_channel& c)
|
||||||
|
{
|
||||||
|
// Nothing to set when a channel has already been installed.
|
||||||
|
if (!tracer) {
|
||||||
|
tracer = &c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fills in the input buffer with the current time.
|
||||||
|
static void format_time(char* buffer, size_t len)
|
||||||
|
{
|
||||||
|
std::time_t t = std::time(nullptr);
|
||||||
|
std::strftime(buffer, len, "%FT%T", std::localtime(&t));
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace srslog {
|
||||||
|
|
||||||
|
void trace_duration_begin(const std::string& category, const std::string& name)
|
||||||
|
{
|
||||||
|
if (!tracer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char fmt_time[24];
|
||||||
|
format_time(fmt_time, sizeof(fmt_time));
|
||||||
|
(*tracer)("[%s] [TID:%0u] Entering \"%s\": %s",
|
||||||
|
fmt_time,
|
||||||
|
(unsigned)::pthread_self(),
|
||||||
|
category,
|
||||||
|
name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void trace_duration_end(const std::string& category, const std::string& name)
|
||||||
|
{
|
||||||
|
if (!tracer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char fmt_time[24];
|
||||||
|
format_time(fmt_time, sizeof(fmt_time));
|
||||||
|
(*tracer)("[%s] [TID:%0u] Leaving \"%s\": %s",
|
||||||
|
fmt_time,
|
||||||
|
(unsigned)::pthread_self(),
|
||||||
|
category,
|
||||||
|
name);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace srslog
|
||||||
|
|
||||||
|
/// Private implementation of the complete event destructor.
|
||||||
|
srslog::detail::scoped_complete_event::~scoped_complete_event()
|
||||||
|
{
|
||||||
|
if (!tracer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto end = std::chrono::steady_clock::now();
|
||||||
|
unsigned long long diff =
|
||||||
|
std::chrono::duration_cast<std::chrono::microseconds>(end - start)
|
||||||
|
.count();
|
||||||
|
|
||||||
|
char fmt_time[24];
|
||||||
|
format_time(fmt_time, sizeof(fmt_time));
|
||||||
|
(*tracer)("[%s] [TID:%0u] Complete event \"%s\" (duration %lld us): %s",
|
||||||
|
fmt_time,
|
||||||
|
(unsigned)::pthread_self(),
|
||||||
|
category,
|
||||||
|
diff,
|
||||||
|
name);
|
||||||
|
}
|
@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013-2020 Software Radio Systems Limited
|
||||||
|
*
|
||||||
|
* This file is part of srsLTE.
|
||||||
|
*
|
||||||
|
* srsLTE is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* srsLTE is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* A copy of the GNU Affero General Public License can be found in
|
||||||
|
* the LICENSE file in the top-level directory of this distribution
|
||||||
|
* and at http://www.gnu.org/licenses/.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SRSLOG_FORMATTER_H
|
||||||
|
#define SRSLOG_FORMATTER_H
|
||||||
|
|
||||||
|
#include "srslte/srslog/bundled/fmt/chrono.h"
|
||||||
|
#include "srslte/srslog/bundled/fmt/ranges.h"
|
||||||
|
#include "srslte/srslog/detail/log_entry.h"
|
||||||
|
|
||||||
|
namespace srslog {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
/// Formats into a hex dump a range of elements, storing the result in the input
|
||||||
|
/// buffer.
|
||||||
|
inline void format_hex_dump(const std::vector<uint8_t>& v,
|
||||||
|
fmt::memory_buffer& buffer)
|
||||||
|
{
|
||||||
|
if (v.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t elements_per_line = 16;
|
||||||
|
|
||||||
|
for (auto i = v.cbegin(), e = v.cend(); i != e;) {
|
||||||
|
auto num_elements =
|
||||||
|
std::min<size_t>(elements_per_line, std::distance(i, e));
|
||||||
|
|
||||||
|
fmt::format_to(buffer,
|
||||||
|
" {:04x}: {:02x}\n",
|
||||||
|
std::distance(v.cbegin(), i),
|
||||||
|
fmt::join(i, i + num_elements, " "));
|
||||||
|
|
||||||
|
std::advance(i, num_elements);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
/// Formats to text all the fields of a log entry,
|
||||||
|
inline std::string format_log_entry_to_text(detail::log_entry&& entry)
|
||||||
|
{
|
||||||
|
fmt::memory_buffer buffer;
|
||||||
|
|
||||||
|
// Time stamp data preparation.
|
||||||
|
std::tm current_time =
|
||||||
|
fmt::gmtime(std::chrono::high_resolution_clock::to_time_t(entry.tp));
|
||||||
|
auto us_fraction = std::chrono::duration_cast<std::chrono::microseconds>(
|
||||||
|
entry.tp.time_since_epoch())
|
||||||
|
.count() %
|
||||||
|
1000000u;
|
||||||
|
fmt::format_to(buffer, "{:%H:%M:%S}.{:06} ", current_time, us_fraction);
|
||||||
|
|
||||||
|
// Format optional fields if present.
|
||||||
|
if (!entry.log_name.empty()) {
|
||||||
|
fmt::format_to(buffer, "[{: <4.4}] ", entry.log_name);
|
||||||
|
}
|
||||||
|
if (entry.log_tag != '\0') {
|
||||||
|
fmt::format_to(buffer, "[{}] ", entry.log_tag);
|
||||||
|
}
|
||||||
|
if (entry.context.enabled) {
|
||||||
|
fmt::format_to(buffer, "[{:5}] ", entry.context.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Message formatting.
|
||||||
|
fmt::format_to(
|
||||||
|
buffer, "{}\n", fmt::vsprintf(entry.fmtstring, std::move(entry.store)));
|
||||||
|
|
||||||
|
// Optional hex dump formatting.
|
||||||
|
detail::format_hex_dump(entry.hex_dump, buffer);
|
||||||
|
|
||||||
|
return fmt::to_string(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace srslog
|
||||||
|
|
||||||
|
#endif // SRSLOG_FORMATTER_H
|
@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013-2020 Software Radio Systems Limited
|
||||||
|
*
|
||||||
|
* This file is part of srsLTE.
|
||||||
|
*
|
||||||
|
* srsLTE is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* srsLTE is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* A copy of the GNU Affero General Public License can be found in
|
||||||
|
* the LICENSE file in the top-level directory of this distribution
|
||||||
|
* and at http://www.gnu.org/licenses/.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SRSLOG_SINK_REPOSITORY_H
|
||||||
|
#define SRSLOG_SINK_REPOSITORY_H
|
||||||
|
|
||||||
|
#include "object_repository.h"
|
||||||
|
#include "sinks/stream_sink.h"
|
||||||
|
|
||||||
|
namespace srslog {
|
||||||
|
|
||||||
|
/// The sink repository stores sink instances associated to an id. Both stdout
|
||||||
|
/// and stderr stream sinks are created on construction so they accessible
|
||||||
|
/// without the need of creating them previously.
|
||||||
|
/// NOTE: Thread safe class.
|
||||||
|
class sink_repository
|
||||||
|
{
|
||||||
|
/// Identifiers for stdout and stderr sinks.
|
||||||
|
static constexpr char stdout_id[] = "stdout#";
|
||||||
|
static constexpr char stderr_id[] = "stderr#";
|
||||||
|
|
||||||
|
object_repository<std::string, std::unique_ptr<sink> > repo;
|
||||||
|
|
||||||
|
public:
|
||||||
|
sink_repository()
|
||||||
|
{
|
||||||
|
//:TODO: GCC5 or lower versions emits an error if we use the new() expression directly, use redundant
|
||||||
|
//piecewise_construct instead.
|
||||||
|
repo.emplace(std::piecewise_construct,
|
||||||
|
std::forward_as_tuple(stdout_id),
|
||||||
|
std::forward_as_tuple(new stream_sink(sink_stream_type::stdout)));
|
||||||
|
repo.emplace(std::piecewise_construct,
|
||||||
|
std::forward_as_tuple(stderr_id),
|
||||||
|
std::forward_as_tuple(new stream_sink(sink_stream_type::stderr)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the instance of the sink that writes to stdout.
|
||||||
|
sink& get_stdout_sink()
|
||||||
|
{
|
||||||
|
auto s = repo.find(stdout_id);
|
||||||
|
assert(s && "stdout sink should always exist");
|
||||||
|
return *(s->get());
|
||||||
|
}
|
||||||
|
const sink& get_stdout_sink() const
|
||||||
|
{
|
||||||
|
const auto s = repo.find(stdout_id);
|
||||||
|
assert(s && "stdout sink should always exist");
|
||||||
|
return *(s->get());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the instance of the sink that writes to stderr.
|
||||||
|
sink& get_stderr_sink()
|
||||||
|
{
|
||||||
|
auto s = repo.find(stderr_id);
|
||||||
|
assert(s && "stderr sink should always exist");
|
||||||
|
return *(s->get());
|
||||||
|
}
|
||||||
|
const sink& get_stderr_sink() const
|
||||||
|
{
|
||||||
|
const auto s = repo.find(stderr_id);
|
||||||
|
assert(s && "stderr sink should always exist");
|
||||||
|
return *(s->get());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Finds a sink with the specified id in the repository. Returns a pointer to
|
||||||
|
/// the sink, otherwise nullptr if not found.
|
||||||
|
sink* find(const std::string& id)
|
||||||
|
{
|
||||||
|
auto p = repo.find(id);
|
||||||
|
return (p) ? p->get() : nullptr;
|
||||||
|
}
|
||||||
|
const sink* find(const std::string& id) const
|
||||||
|
{
|
||||||
|
const auto p = repo.find(id);
|
||||||
|
return (p) ? p->get() : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an instance of a sink specified by the input arguments.
|
||||||
|
template <typename... Args>
|
||||||
|
sink& fetch_sink(Args&&... args)
|
||||||
|
{
|
||||||
|
return *repo.emplace(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a copy of the list of registered sinks.
|
||||||
|
std::vector<sink*> contents() const
|
||||||
|
{
|
||||||
|
auto repo_contents = repo.contents();
|
||||||
|
|
||||||
|
std::vector<sink*> data;
|
||||||
|
data.reserve(repo_contents.size());
|
||||||
|
for (const auto& s : repo_contents) {
|
||||||
|
data.push_back(s->get());
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr char sink_repository::stdout_id[];
|
||||||
|
constexpr char sink_repository::stderr_id[];
|
||||||
|
|
||||||
|
} // namespace srslog
|
||||||
|
|
||||||
|
#endif // SRSLOG_SINK_REPOSITORY_H
|
@ -0,0 +1,196 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013-2020 Software Radio Systems Limited
|
||||||
|
*
|
||||||
|
* This file is part of srsLTE.
|
||||||
|
*
|
||||||
|
* srsLTE is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* srsLTE is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* A copy of the GNU Affero General Public License can be found in
|
||||||
|
* the LICENSE file in the top-level directory of this distribution
|
||||||
|
* and at http://www.gnu.org/licenses/.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "srslte/srslog/srslog_c.h"
|
||||||
|
#include "srslte/srslog/srslog.h"
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstdarg>
|
||||||
|
|
||||||
|
using namespace srslog;
|
||||||
|
|
||||||
|
template <typename To, typename From>
|
||||||
|
static inline To* c_cast(From* x)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<To*>(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper to format the input argument list writing it into a channel.
|
||||||
|
static void log_to(log_channel& c, const char* fmt, std::va_list args)
|
||||||
|
{
|
||||||
|
char buffer[1024];
|
||||||
|
std::vsnprintf(buffer, sizeof(buffer) - 1, fmt, args);
|
||||||
|
c(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void srslog_init(void)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void srslog_set_default_sink(srslog_sink* s)
|
||||||
|
{
|
||||||
|
assert(s && "Expected a valid sink");
|
||||||
|
set_default_sink(*c_cast<sink>(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
srslog_sink* srslog_get_default_sink(void)
|
||||||
|
{
|
||||||
|
return c_cast<srslog_sink>(&get_default_sink());
|
||||||
|
}
|
||||||
|
|
||||||
|
srslog_log_channel* srslog_fetch_log_channel(const char* id)
|
||||||
|
{
|
||||||
|
return c_cast<srslog_log_channel>(&fetch_log_channel(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
srslog_log_channel* srslog_find_log_channel(const char* id)
|
||||||
|
{
|
||||||
|
return c_cast<srslog_log_channel>(find_log_channel(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
void srslog_set_log_channel_enabled(srslog_log_channel* channel,
|
||||||
|
srslog_bool enabled)
|
||||||
|
{
|
||||||
|
assert(channel && "Expected a valid channel");
|
||||||
|
c_cast<log_channel>(channel)->set_enabled(enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
srslog_bool srslog_is_log_channel_enabled(srslog_log_channel* channel)
|
||||||
|
{
|
||||||
|
assert(channel && "Expected a valid channel");
|
||||||
|
return c_cast<log_channel>(channel)->enabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* srslog_get_log_channel_id(srslog_log_channel* channel)
|
||||||
|
{
|
||||||
|
assert(channel && "Expected a valid channel");
|
||||||
|
return c_cast<log_channel>(channel)->id().c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
void srslog_log(srslog_log_channel* channel, const char* fmt, ...)
|
||||||
|
{
|
||||||
|
assert(channel && "Expected a valid channel");
|
||||||
|
|
||||||
|
std::va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
log_to(*c_cast<log_channel>(channel), fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
srslog_logger* srslog_fetch_default_logger(const char* id)
|
||||||
|
{
|
||||||
|
return c_cast<srslog_logger>(&fetch_basic_logger(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
srslog_logger* srslog_find_default_logger(const char* id)
|
||||||
|
{
|
||||||
|
return c_cast<srslog_logger>(find_logger<basic_logger>(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
void srslog_debug(srslog_logger* log, const char* fmt, ...)
|
||||||
|
{
|
||||||
|
assert(log && "Expected a valid logger");
|
||||||
|
|
||||||
|
std::va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
log_to(c_cast<basic_logger>(log)->debug, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void srslog_info(srslog_logger* log, const char* fmt, ...)
|
||||||
|
{
|
||||||
|
assert(log && "Expected a valid logger");
|
||||||
|
|
||||||
|
std::va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
log_to(c_cast<basic_logger>(log)->info, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void srslog_warning(srslog_logger* log, const char* fmt, ...)
|
||||||
|
{
|
||||||
|
assert(log && "Expected a valid logger");
|
||||||
|
|
||||||
|
std::va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
log_to(c_cast<basic_logger>(log)->warning, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void srslog_error(srslog_logger* log, const char* fmt, ...)
|
||||||
|
{
|
||||||
|
assert(log && "Expected a valid logger");
|
||||||
|
|
||||||
|
std::va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
log_to(c_cast<basic_logger>(log)->error, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* srslog_get_logger_id(srslog_logger* log)
|
||||||
|
{
|
||||||
|
assert(log && "Expected a valid logger");
|
||||||
|
return c_cast<basic_logger>(log)->id().c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Translate the C API level enum to basic_levels.
|
||||||
|
static basic_levels convert_c_enum_to_basic_levels(srslog_log_levels lvl)
|
||||||
|
{
|
||||||
|
switch (lvl) {
|
||||||
|
case srslog_lvl_debug:
|
||||||
|
return basic_levels::debug;
|
||||||
|
case srslog_lvl_info:
|
||||||
|
return basic_levels::info;
|
||||||
|
case srslog_lvl_warning:
|
||||||
|
return basic_levels ::warning;
|
||||||
|
case srslog_lvl_error:
|
||||||
|
return basic_levels::error;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(false && "Invalid enum value");
|
||||||
|
return basic_levels::error;
|
||||||
|
}
|
||||||
|
|
||||||
|
void srslog_set_logger_level(srslog_logger* log, srslog_log_levels lvl)
|
||||||
|
{
|
||||||
|
assert(log && "Expected a valid logger");
|
||||||
|
c_cast<basic_logger>(log)->set_level(convert_c_enum_to_basic_levels(lvl));
|
||||||
|
}
|
||||||
|
|
||||||
|
srslog_sink* srslog_find_sink(const char* id)
|
||||||
|
{
|
||||||
|
return c_cast<srslog_sink>(find_sink(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
srslog_sink* srslog_fetch_stdout_sink(void)
|
||||||
|
{
|
||||||
|
return c_cast<srslog_sink>(&fetch_stdout_sink());
|
||||||
|
}
|
||||||
|
|
||||||
|
srslog_sink* srslog_fetch_stderr_sink(void)
|
||||||
|
{
|
||||||
|
return c_cast<srslog_sink>(&fetch_stderr_sink());
|
||||||
|
}
|
||||||
|
|
||||||
|
srslog_sink* srslog_fetch_file_sink(const char* path, size_t max_size)
|
||||||
|
{
|
||||||
|
return c_cast<srslog_sink>(&fetch_file_sink(path, max_size));
|
||||||
|
}
|
@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013-2020 Software Radio Systems Limited
|
||||||
|
*
|
||||||
|
* This file is part of srsLTE.
|
||||||
|
*
|
||||||
|
* srsLTE is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* srsLTE is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* A copy of the GNU Affero General Public License can be found in
|
||||||
|
* the LICENSE file in the top-level directory of this distribution
|
||||||
|
* and at http://www.gnu.org/licenses/.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "srslte/srslog/event_trace.h"
|
||||||
|
#include "srslte/srslog/log_channel.h"
|
||||||
|
#include "srslte/srslog/sink.h"
|
||||||
|
#include "testing_helpers.h"
|
||||||
|
|
||||||
|
using namespace srslog;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
/// A Dummy implementation of a sink.
|
||||||
|
class sink_dummy : public sink
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
detail::error_string write(detail::memory_buffer buffer) override
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
detail::error_string flush() override { return {}; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A Spy implementation of a log backend. Tests can query if the push method
|
||||||
|
/// has been invoked.
|
||||||
|
class backend_spy : public detail::log_backend
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void start() override {}
|
||||||
|
|
||||||
|
void push(detail::log_entry&& entry) override
|
||||||
|
{
|
||||||
|
std::string result = fmt::vsprintf(entry.fmtstring, std::move(entry.store));
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_running() const override { return true; }
|
||||||
|
|
||||||
|
void reset() { count = 0; }
|
||||||
|
|
||||||
|
unsigned push_invocation_count() const { return count; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned count = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
static bool
|
||||||
|
when_tracing_with_duration_event_then_two_events_are_generated(backend_spy& spy)
|
||||||
|
{
|
||||||
|
trace_duration_begin("a", "b");
|
||||||
|
ASSERT_EQ(spy.push_invocation_count(), 1);
|
||||||
|
|
||||||
|
trace_duration_end("a", "b");
|
||||||
|
ASSERT_EQ(spy.push_invocation_count(), 2);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
when_tracing_with_complete_event_then_one_event_is_generated(backend_spy& spy)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
trace_complete_event("a", "b");
|
||||||
|
}
|
||||||
|
ASSERT_EQ(spy.push_invocation_count(), 1);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
sink_dummy s;
|
||||||
|
backend_spy backend;
|
||||||
|
log_channel c("test", s, backend);
|
||||||
|
|
||||||
|
// Inject our spy into the framework.
|
||||||
|
event_trace_init(c);
|
||||||
|
|
||||||
|
TEST_FUNCTION(when_tracing_with_duration_event_then_two_events_are_generated,
|
||||||
|
backend);
|
||||||
|
backend.reset();
|
||||||
|
TEST_FUNCTION(when_tracing_with_complete_event_then_one_event_is_generated,
|
||||||
|
backend);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -0,0 +1,121 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013-2020 Software Radio Systems Limited
|
||||||
|
*
|
||||||
|
* This file is part of srsLTE.
|
||||||
|
*
|
||||||
|
* srsLTE is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* srsLTE is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* A copy of the GNU Affero General Public License can be found in
|
||||||
|
* the LICENSE file in the top-level directory of this distribution
|
||||||
|
* and at http://www.gnu.org/licenses/.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "src/srslog/formatter.h"
|
||||||
|
#include "testing_helpers.h"
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
|
using namespace srslog;
|
||||||
|
|
||||||
|
/// Helper to build a log entry.
|
||||||
|
static detail::log_entry build_log_entry()
|
||||||
|
{
|
||||||
|
// Create a time point 50000us from epoch.
|
||||||
|
using tp_ty = std::chrono::time_point<std::chrono::high_resolution_clock>;
|
||||||
|
tp_ty tp(std::chrono::microseconds(50000));
|
||||||
|
|
||||||
|
fmt::dynamic_format_arg_store<fmt::printf_context> store;
|
||||||
|
store.push_back(88);
|
||||||
|
|
||||||
|
return {nullptr, tp, {10, true}, "Text %d", std::move(store), "ABC", 'Z'};
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool when_fully_filled_log_entry_then_result_everything_is_formatted()
|
||||||
|
{
|
||||||
|
std::string result = format_log_entry_to_text(build_log_entry());
|
||||||
|
std::string expected = "00:00:00.050000 [ABC ] [Z] [ 10] Text 88\n";
|
||||||
|
|
||||||
|
ASSERT_EQ(result, expected);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool when_log_entry_without_name_is_passed_then_name_is_not_formatted()
|
||||||
|
{
|
||||||
|
auto entry = build_log_entry();
|
||||||
|
entry.log_name = "";
|
||||||
|
|
||||||
|
std::string result = format_log_entry_to_text(std::move(entry));
|
||||||
|
std::string expected = "00:00:00.050000 [Z] [ 10] Text 88\n";
|
||||||
|
|
||||||
|
ASSERT_EQ(result, expected);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool when_log_entry_without_tag_is_passed_then_tag_is_not_formatted()
|
||||||
|
{
|
||||||
|
auto entry = build_log_entry();
|
||||||
|
entry.log_tag = '\0';
|
||||||
|
|
||||||
|
std::string result = format_log_entry_to_text(std::move(entry));
|
||||||
|
std::string expected = "00:00:00.050000 [ABC ] [ 10] Text 88\n";
|
||||||
|
|
||||||
|
ASSERT_EQ(result, expected);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
when_log_entry_without_context_is_passed_then_context_is_not_formatted()
|
||||||
|
{
|
||||||
|
auto entry = build_log_entry();
|
||||||
|
entry.context.enabled = false;
|
||||||
|
|
||||||
|
std::string result = format_log_entry_to_text(std::move(entry));
|
||||||
|
std::string expected = "00:00:00.050000 [ABC ] [Z] Text 88\n";
|
||||||
|
|
||||||
|
ASSERT_EQ(result, expected);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool when_log_entry_with_hex_dump_is_passed_then_hex_dump_is_formatted()
|
||||||
|
{
|
||||||
|
auto entry = build_log_entry();
|
||||||
|
entry.hex_dump.resize(20);
|
||||||
|
std::iota(entry.hex_dump.begin(), entry.hex_dump.end(), 0);
|
||||||
|
|
||||||
|
std::string result = format_log_entry_to_text(std::move(entry));
|
||||||
|
std::string expected =
|
||||||
|
"00:00:00.050000 [ABC ] [Z] [ 10] Text 88\n"
|
||||||
|
" 0000: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n"
|
||||||
|
" 0010: 10 11 12 13\n";
|
||||||
|
|
||||||
|
ASSERT_EQ(result, expected);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
TEST_FUNCTION(
|
||||||
|
when_fully_filled_log_entry_then_result_everything_is_formatted);
|
||||||
|
TEST_FUNCTION(
|
||||||
|
when_log_entry_without_name_is_passed_then_name_is_not_formatted);
|
||||||
|
TEST_FUNCTION(when_log_entry_without_tag_is_passed_then_tag_is_not_formatted);
|
||||||
|
TEST_FUNCTION(
|
||||||
|
when_log_entry_without_context_is_passed_then_context_is_not_formatted);
|
||||||
|
TEST_FUNCTION(
|
||||||
|
when_log_entry_with_hex_dump_is_passed_then_hex_dump_is_formatted);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue