mirror of https://github.com/pvnis/srsRAN_4G.git
Merge branch 'next' into agpl_next
commit
910dc5af86
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,70 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2020 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSENB_ENB_EVENTS_H
|
||||
#define SRSENB_ENB_EVENTS_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
namespace srslog {
|
||||
class log_channel;
|
||||
}
|
||||
|
||||
namespace srsenb {
|
||||
|
||||
/// This interface logs different kinds of events to the configured channel. By default, if no log channel is configured
|
||||
/// logging will be disabled.
|
||||
class event_logger_interface
|
||||
{
|
||||
public:
|
||||
virtual ~event_logger_interface() = default;
|
||||
|
||||
/// Logs into the underlying log channel the RRC connected event.
|
||||
virtual void log_rrc_connected(unsigned cause) = 0;
|
||||
|
||||
/// Logs into the underlying log channel the RRC disconnected event.
|
||||
virtual void log_rrc_disconnect(unsigned reason) = 0;
|
||||
|
||||
/// Logs into the underlying log channel the S1 context create event.
|
||||
virtual void log_s1_ctx_create(uint32_t mme_id, uint32_t enb_id, uint16_t rnti) = 0;
|
||||
|
||||
/// Logs into the underlying log channel the S1 context delete event.
|
||||
virtual void log_s1_ctx_delete(uint32_t mme_id, uint32_t enb_id, uint16_t rnti) = 0;
|
||||
|
||||
/// Logs into the underlying log channel the when a sector has been started.
|
||||
virtual void log_sector_start(uint32_t cc_idx, uint32_t pci, uint32_t cell_id) = 0;
|
||||
|
||||
/// Logs into the underlying log channel the when a sector has been stopped.
|
||||
virtual void log_sector_stop(uint32_t cc_idx, uint32_t pci, uint32_t cell_id) = 0;
|
||||
};
|
||||
|
||||
/// Singleton class to provide global access to the event_logger_interface interface.
|
||||
class event_logger
|
||||
{
|
||||
event_logger() = default;
|
||||
|
||||
public:
|
||||
/// Returns the instance of the event logger.
|
||||
static event_logger_interface& get();
|
||||
|
||||
/// Uses the specified log channel for event logging.
|
||||
/// NOTE: This method is not thread safe.
|
||||
static void configure(srslog::log_channel& c);
|
||||
|
||||
private:
|
||||
static std::unique_ptr<event_logger_interface> pimpl;
|
||||
};
|
||||
|
||||
} // namespace srsenb
|
||||
|
||||
#endif // SRSENB_ENB_EVENTS_H
|
@ -0,0 +1,67 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2020 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSLTE_POLAR_INTERLEAVER_H
|
||||
#define SRSLTE_POLAR_INTERLEAVER_H
|
||||
|
||||
#include "srslte/config.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define SRSLTE_POLAR_INTERLEAVER_K_MAX_IL 164
|
||||
|
||||
/**
|
||||
* * @brief Implements generic Polar code interleaver as described in TS 38.212 V15.9.0 Section 5.3.1.1
|
||||
*
|
||||
* @attention The input and output data cannot be the same.
|
||||
*
|
||||
* @param in Input data pointer
|
||||
* @param out Output data pointer
|
||||
* @param S Data element size in bytes
|
||||
* @param K Number of elements
|
||||
* @param dir Set to true for encoder and false for decoder
|
||||
*/
|
||||
SRSLTE_API void srslte_polar_interleaver_run(const void* in, void* out, uint32_t S, uint32_t K, bool dir);
|
||||
|
||||
#define SRSLTE_POLAR_INTERLEAVE_GEN(NAME, TYPE) \
|
||||
static inline void srslte_polar_interleaver_run_##NAME(const TYPE* in, void* out, uint32_t K, bool dir) \
|
||||
{ \
|
||||
srslte_polar_interleaver_run(in, out, (uint32_t)sizeof(TYPE), K, dir); \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Implements Polar code interleaver as described in TS 38.212 V15.9.0 Section 5.3.1.1
|
||||
*
|
||||
* @attention The input and output data cannot be the same.
|
||||
*
|
||||
* @param in unsigned 16 bit Input data
|
||||
* @param out unsigned 16 bit Output data
|
||||
* @param K Number of elements
|
||||
* @param dir Set to true for encoder and false for decoder
|
||||
*/
|
||||
SRSLTE_POLAR_INTERLEAVE_GEN(u16, uint16_t)
|
||||
|
||||
/**
|
||||
* @brief Implements Polar code interleaver as described in TS 38.212 V15.9.0 Section 5.3.1.1
|
||||
*
|
||||
* @attention The input and output data cannot be the same.
|
||||
*
|
||||
* @param in unsigned 8 bit Input data
|
||||
* @param out unsigned 8 bit Output data
|
||||
* @param K Number of elements
|
||||
* @param dir Set to true for encoder and false for decoder
|
||||
*/
|
||||
SRSLTE_POLAR_INTERLEAVE_GEN(u8, uint8_t)
|
||||
|
||||
#undef SRSLTE_POLAR_INTERLEAVE_GEN
|
||||
|
||||
#endif // SRSLTE_POLAR_INTERLEAVER_H
|
@ -0,0 +1,250 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2020 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSLOG_CONTEXT_H
|
||||
#define SRSLOG_CONTEXT_H
|
||||
|
||||
#include "srslte/srslog/detail/support/tmp_utils.h"
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
|
||||
namespace srslog {
|
||||
|
||||
/// Metric formatting kinds for textual conversion.
|
||||
enum class metric_kind {
|
||||
numeric, /// Metric represents a numeric value.
|
||||
string /// Metric represents a string.
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
/// This metrics container class is a wrapper to simplify access to the elements
|
||||
/// of the underlying tuple that stores metrics and metric sets.
|
||||
template <typename... Ts>
|
||||
struct metrics_container {
|
||||
/// Writes the arg value to metric T.
|
||||
template <typename T, typename Arg>
|
||||
void write(Arg&& arg)
|
||||
{
|
||||
constexpr std::size_t index = detail::get_type_index_in_tuple<T, Ts...>();
|
||||
std::get<index>(metrics).value = std::forward<Arg>(arg);
|
||||
}
|
||||
|
||||
/// Returns the value of metric T.
|
||||
template <typename T>
|
||||
auto read() const -> const decltype(T::value)&
|
||||
{
|
||||
constexpr std::size_t index = detail::get_type_index_in_tuple<T, Ts...>();
|
||||
return std::get<index>(metrics).value;
|
||||
}
|
||||
|
||||
/// Returns the element of type T.
|
||||
template <typename T>
|
||||
T& get()
|
||||
{
|
||||
constexpr std::size_t index = detail::get_type_index_in_tuple<T, Ts...>();
|
||||
return std::get<index>(metrics);
|
||||
}
|
||||
|
||||
/// Returns the element of type T.
|
||||
template <typename T>
|
||||
const T& get() const
|
||||
{
|
||||
constexpr std::size_t index = detail::get_type_index_in_tuple<T, Ts...>();
|
||||
return std::get<index>(metrics);
|
||||
}
|
||||
|
||||
/// Returns the element in the specified index of list T.
|
||||
/// NOTE: T must have implemented the T operator.
|
||||
template <typename T>
|
||||
auto at(std::size_t i) -> typename T::value_type&
|
||||
{
|
||||
constexpr std::size_t index = detail::get_type_index_in_tuple<T, Ts...>();
|
||||
auto& elem = std::get<index>(metrics);
|
||||
assert(i < elem.size() && "Invalid index");
|
||||
return elem[i];
|
||||
}
|
||||
|
||||
/// Returns the element in the specified index of list T.
|
||||
/// NOTE: T must have implemented the T operator.
|
||||
template <typename T>
|
||||
auto at(std::size_t i) const -> const typename T::value_type&
|
||||
{
|
||||
constexpr std::size_t index = detail::get_type_index_in_tuple<T, Ts...>();
|
||||
const auto& elem = std::get<index>(metrics);
|
||||
assert(i < elem.size() && "Invalid index");
|
||||
return elem[i];
|
||||
}
|
||||
|
||||
/// Returns the raw contents of the metric set as a tuple.
|
||||
const std::tuple<Ts...>& contents() const { return metrics; }
|
||||
|
||||
private:
|
||||
std::tuple<Ts...> metrics;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// A generic list to store metric sets of the same type.
|
||||
template <typename Name, typename T>
|
||||
struct metric_list : public T {
|
||||
/// Returns the name of the list.
|
||||
static const char* name() { return Name::name(); }
|
||||
};
|
||||
|
||||
/// Template specializations of this struct allow configuring what formatting
|
||||
/// kind should be used for a concrete metric.
|
||||
/// By default treat all metrics as strings.
|
||||
template <typename T, typename = void>
|
||||
struct metric_kind_selector {
|
||||
static const metric_kind kind = metric_kind::string;
|
||||
};
|
||||
|
||||
/// A metric is the most basic object that composes a context. It is generally
|
||||
/// used to represent any kind of state of a program.
|
||||
/// It stores a value of type T associated with a name and the units.
|
||||
template <typename Ty, typename Name, typename Units>
|
||||
struct metric {
|
||||
/// Value of the metric.
|
||||
Ty value{};
|
||||
|
||||
/// Returns the name of the metric.
|
||||
static const char* name() { return Name::name(); }
|
||||
|
||||
/// Returns the units of the metric.
|
||||
static const char* units() { return Units::units(); }
|
||||
|
||||
/// Returns the formatting kind of the metric.
|
||||
static metric_kind kind()
|
||||
{
|
||||
return metric_kind_selector<metric<Ty, Name, Units>>::kind;
|
||||
}
|
||||
};
|
||||
|
||||
/// Template specialization that tags metrics with arithmetic values (integers
|
||||
/// and floating point) as numeric.
|
||||
template <typename Ty, typename Name, typename Units>
|
||||
struct metric_kind_selector<
|
||||
metric<Ty, Name, Units>,
|
||||
typename std::enable_if<std::is_arithmetic<Ty>::value>::type> {
|
||||
static const metric_kind kind = metric_kind::numeric;
|
||||
};
|
||||
|
||||
/// A metric set is a group of metrics that share a logical relation. Allows
|
||||
/// storing and mixing other metric sets and metrics for building complex
|
||||
/// structures.
|
||||
template <typename Name, typename... Ts>
|
||||
struct metric_set : public detail::metrics_container<Ts...> {
|
||||
/// Name of the metric set.
|
||||
static const char* name() { return Name::name(); }
|
||||
};
|
||||
|
||||
/// A context captures the state of different parts of a program grouping metric
|
||||
/// sets. It is the root element of the metrics structure and allows mixing and
|
||||
/// storing other metric sets and metrics.
|
||||
template <typename... Ts>
|
||||
struct context : public detail::metrics_container<Ts...> {
|
||||
explicit context(std::string n) : name_str(std::move(n)) {}
|
||||
|
||||
/// Name of the context.
|
||||
const std::string& name() const { return name_str; }
|
||||
|
||||
private:
|
||||
const std::string name_str;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
/// Builds a metric set type using a list of metric, metric sets or list types.
|
||||
/// eg: using my_metric_t = srslog::build_metric_set_type<m1_t, set1_t, m2_t>;
|
||||
/// NOTE: Adding duplicated types into the list is not allowed.
|
||||
template <typename Name, typename... Ts>
|
||||
using build_metric_set_type =
|
||||
metric_set<Name, typename std::decay<Ts>::type...>;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// Builds a context type using a list of metric set types.
|
||||
/// eg: using my_context_t = srslog::build_context_type<set1_t, set2_t>;
|
||||
/// NOTE: Adding duplicated types into the list is not allowed.
|
||||
template <typename... Ts>
|
||||
using build_context_type = context<typename std::decay<Ts>::type...>;
|
||||
|
||||
/// This macro defines a new metric type using the following attributes:
|
||||
/// a) name: encoded as a string.
|
||||
/// b) Metric type: type identifier to create objects for this metric.
|
||||
/// c) Value type: type of the underlying metric value.
|
||||
/// d) Units: encoded as a string, leave as empty string for no units.
|
||||
///
|
||||
/// The following example declares a metric with the following attributes:
|
||||
/// a) metric type: my_metric_t
|
||||
/// b) metric value type: float
|
||||
/// c) units: MB/s
|
||||
/// d) name: Throughput
|
||||
/// DECLARE_METRIC("Throughput", my_metric_t, float, "MB/s");
|
||||
#define DECLARE_METRIC(_name_rep, _type, _value_type, _units) \
|
||||
namespace metric_info { \
|
||||
struct _type##__units { \
|
||||
static const char* units() { return _units; } \
|
||||
}; \
|
||||
struct _type##__name_rep { \
|
||||
static const char* name() { return _name_rep; } \
|
||||
}; \
|
||||
} \
|
||||
using _type = srslog::metric<typename std::decay<_value_type>::type, \
|
||||
metric_info::_type##__name_rep, \
|
||||
metric_info::_type##__units>
|
||||
|
||||
/// This macro defines a new metric set type using the following attributes:
|
||||
/// a) name: encoded as a string.
|
||||
/// b) Metric set type: type identifier to create objects for this metric set.
|
||||
/// c) Type list: list of types this set will hold (other sets, metrics,
|
||||
/// lists).
|
||||
///
|
||||
/// The following example declares a metric set of three elements (two metrics
|
||||
/// and one set) with the following attributes:
|
||||
/// a) metric type: my_set_t
|
||||
/// b) name: my_set
|
||||
/// b) type list: metric1_t, metric2_t, set2_t
|
||||
/// DECLARE_METRIC_SET("my_set", my_set_t, metric1_t, metric2_t, set2_t);
|
||||
#define DECLARE_METRIC_SET(_name_rep, _type, ...) \
|
||||
namespace metric_set_info { \
|
||||
struct _type##__name_rep { \
|
||||
static const char* name() { return _name_rep; } \
|
||||
}; \
|
||||
} \
|
||||
using _type = srslog::detail:: \
|
||||
build_metric_set_type<metric_set_info::_type##__name_rep, __VA_ARGS__>
|
||||
|
||||
/// This macro defines a list of metric sets of the same type:
|
||||
/// a) name: encoded as a string.
|
||||
/// b) List type: type identifier to create objects for this list.
|
||||
/// c) Underlying type: type of the underlying list (vector, array, ...).
|
||||
///
|
||||
/// The following example declares a list of metrics sets of type set1_t with
|
||||
/// the following attributes:
|
||||
/// a) list type: my_list_t
|
||||
/// b) name: my_list
|
||||
/// b) underlying type: std::vector<set1_t>
|
||||
/// DECLARE_METRIC_LIST("my_list", my_list_t, std::vector<set1_t>);
|
||||
#define DECLARE_METRIC_LIST(_name_rep, _type, _list_type) \
|
||||
namespace list_info { \
|
||||
struct _type##__name_rep { \
|
||||
static const char* name() { return _name_rep; } \
|
||||
}; \
|
||||
} \
|
||||
using _type = srslog::metric_list<list_info::_type##__name_rep, \
|
||||
typename std::decay<_list_type>::type>
|
||||
|
||||
} // namespace srslog
|
||||
|
||||
#endif // SRSLOG_CONTEXT_H
|
@ -0,0 +1,47 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2020 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSLOG_DETAIL_LOG_ENTRY_METADATA_H
|
||||
#define SRSLOG_DETAIL_LOG_ENTRY_METADATA_H
|
||||
|
||||
#include "srslte/srslog/bundled/fmt/printf.h"
|
||||
#include <chrono>
|
||||
|
||||
namespace srslog {
|
||||
|
||||
namespace detail {
|
||||
|
||||
/// This structure gives the user a way to log generic information as a context.
|
||||
//:TODO: legacy struct, will get replaced by the new context framework.
|
||||
struct log_context {
|
||||
/// Generic context value.
|
||||
uint32_t value;
|
||||
/// When true, the context value will be printed in the log entry.
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
/// Metadata fields carried for each log entry.
|
||||
struct log_entry_metadata {
|
||||
std::chrono::high_resolution_clock::time_point tp;
|
||||
log_context context;
|
||||
std::string fmtstring;
|
||||
fmt::dynamic_format_arg_store<fmt::printf_context> store;
|
||||
std::string log_name;
|
||||
char log_tag;
|
||||
std::vector<uint8_t> hex_dump;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace srslog
|
||||
|
||||
#endif // SRSLOG_DETAIL_LOG_ENTRY_METADATA_H
|
@ -0,0 +1,70 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2020 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSLOG_DETAIL_SUPPORT_TMP_UTILS_H
|
||||
#define SRSLOG_DETAIL_SUPPORT_TMP_UTILS_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <tuple>
|
||||
|
||||
namespace srslog {
|
||||
|
||||
namespace detail {
|
||||
|
||||
///
|
||||
/// Implementation of the std::index_sequence C++14 library utility.
|
||||
///
|
||||
|
||||
template <std::size_t...>
|
||||
struct index_sequence {};
|
||||
|
||||
template <std::size_t N, std::size_t... Next>
|
||||
struct index_sequence_helper
|
||||
: public index_sequence_helper<N - 1U, N - 1U, Next...> {};
|
||||
|
||||
template <std::size_t... Next>
|
||||
struct index_sequence_helper<0U, Next...> {
|
||||
using type = index_sequence<Next...>;
|
||||
};
|
||||
|
||||
template <std::size_t N>
|
||||
using make_index_sequence = typename index_sequence_helper<N>::type;
|
||||
|
||||
///
|
||||
/// Implementation of the std::get<T> C++14 library utility.
|
||||
///
|
||||
|
||||
template <typename T, typename Tuple>
|
||||
struct tuple_index;
|
||||
|
||||
template <typename T, typename... Ts>
|
||||
struct tuple_index<T, std::tuple<T, Ts...>> {
|
||||
static constexpr std::size_t value = 0;
|
||||
};
|
||||
|
||||
template <typename T, typename U, typename... Ts>
|
||||
struct tuple_index<T, std::tuple<U, Ts...>> {
|
||||
static constexpr std::size_t value =
|
||||
1 + tuple_index<T, std::tuple<Ts...>>::value;
|
||||
};
|
||||
|
||||
template <typename T, typename... Ts>
|
||||
constexpr std::size_t get_type_index_in_tuple()
|
||||
{
|
||||
return tuple_index<T, std::tuple<Ts...>>::value;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace srslog
|
||||
|
||||
#endif // SRSLOG_DETAIL_SUPPORT_TMP_UTILS_H
|
@ -0,0 +1,185 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2020 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSLOG_FORMATTER_H
|
||||
#define SRSLOG_FORMATTER_H
|
||||
|
||||
#include "srslte/srslog/bundled/fmt/format.h"
|
||||
#include "srslte/srslog/context.h"
|
||||
|
||||
namespace srslog {
|
||||
|
||||
namespace detail {
|
||||
struct log_entry_metadata;
|
||||
}
|
||||
|
||||
/// The generic metric value formatter.
|
||||
template <typename T>
|
||||
struct metric_value_formatter {
|
||||
metric_value_formatter() = delete;
|
||||
/// All specializations should implement the following method with signature:
|
||||
/// template <typename T>
|
||||
/// void format(const T& v, fmt::memory_buffer& buffer)
|
||||
};
|
||||
|
||||
/// Default metric value formatter. Users that want to override this behaviour
|
||||
/// should add an specialization of the metric they want to customize.
|
||||
template <typename Ty, typename Name, typename Units>
|
||||
struct metric_value_formatter<metric<Ty, Name, Units>> {
|
||||
template <typename T>
|
||||
void format(const T& v, fmt::memory_buffer& buffer)
|
||||
{
|
||||
fmt::format_to(buffer, "{}", v);
|
||||
}
|
||||
};
|
||||
|
||||
/// This is the base class that provides a common framework to format log
|
||||
/// entries to different kinds of formats. User should implement two different
|
||||
/// kinds of formats:
|
||||
/// a) Basic log entry formatting.
|
||||
/// b) Generic context formatting.
|
||||
///
|
||||
/// For context formatting, callbacks are provided so that derived classes
|
||||
/// handle specific formatting rules.
|
||||
class log_formatter
|
||||
{
|
||||
public:
|
||||
virtual ~log_formatter() = default;
|
||||
|
||||
/// Returns a copy of the formatter.
|
||||
virtual std::unique_ptr<log_formatter> clone() const = 0;
|
||||
|
||||
/// Formats the log entry into the input buffer.
|
||||
virtual void format(detail::log_entry_metadata&& metadata,
|
||||
fmt::memory_buffer& buffer) = 0;
|
||||
|
||||
/// Formats the context and log entry into the input buffer.
|
||||
template <typename... Ts>
|
||||
void format_ctx(const srslog::context<Ts...>& ctx,
|
||||
detail::log_entry_metadata&& metadata,
|
||||
fmt::memory_buffer& buffer)
|
||||
{
|
||||
format_context_begin(metadata, ctx.name(), sizeof...(Ts), buffer);
|
||||
iterate_tuple(ctx.contents(),
|
||||
1,
|
||||
buffer,
|
||||
detail::make_index_sequence<sizeof...(Ts)>{});
|
||||
format_context_end(metadata, ctx.name(), buffer);
|
||||
}
|
||||
|
||||
private:
|
||||
/// Processes all elements in a tuple.
|
||||
template <typename... Ts, std::size_t... Is>
|
||||
void iterate_tuple(const std::tuple<Ts...>& t,
|
||||
unsigned level,
|
||||
fmt::memory_buffer& buffer,
|
||||
detail::index_sequence<Is...>)
|
||||
{
|
||||
(void)std::initializer_list<int>{
|
||||
(process_element(std::get<Is>(t), level, buffer), 0)...};
|
||||
}
|
||||
|
||||
/// Processes the input metric set.
|
||||
template <typename Name, typename... Ts>
|
||||
void process_element(const metric_set<Name, Ts...>& ms,
|
||||
unsigned level,
|
||||
fmt::memory_buffer& buffer)
|
||||
{
|
||||
format_metric_set_begin(ms.name(), sizeof...(Ts), level, buffer);
|
||||
iterate_tuple(ms.contents(),
|
||||
level + 1,
|
||||
buffer,
|
||||
detail::make_index_sequence<sizeof...(Ts)>{});
|
||||
format_metric_set_end(ms.name(), level, buffer);
|
||||
}
|
||||
|
||||
/// Processes the input metric list.
|
||||
template <typename Name, typename T>
|
||||
void process_element(const metric_list<Name, T>& list,
|
||||
unsigned level,
|
||||
fmt::memory_buffer& buffer)
|
||||
{
|
||||
format_list_begin(list.name(), list.size(), level, buffer);
|
||||
for (const auto& elem : list) {
|
||||
process_element(elem, level + 1, buffer);
|
||||
}
|
||||
format_list_end(list.name(), level, buffer);
|
||||
}
|
||||
|
||||
/// Processes the input metric.
|
||||
template <typename Ty, typename Name, typename Units>
|
||||
void process_element(const metric<Ty, Name, Units>& t,
|
||||
unsigned level,
|
||||
fmt::memory_buffer& buffer)
|
||||
{
|
||||
fmt::memory_buffer value;
|
||||
metric_value_formatter<typename std::decay<decltype(t)>::type>{}.format(
|
||||
t.value, value);
|
||||
|
||||
format_metric(
|
||||
t.name(), fmt::to_string(value), t.units(), t.kind(), level, buffer);
|
||||
}
|
||||
|
||||
private:
|
||||
/// Derived classes should implement the following callbacks to format metric
|
||||
/// objects. Each callback is invoked at a different place of the formatting
|
||||
/// algorithm.
|
||||
|
||||
/// This callback gets called at the beginning of the context formatting
|
||||
/// algorithm.
|
||||
virtual void format_context_begin(const detail::log_entry_metadata& md,
|
||||
const std::string& ctx_name,
|
||||
unsigned size,
|
||||
fmt::memory_buffer& buffer) = 0;
|
||||
|
||||
/// This callback gets called at the end of the context formatting algorithm.
|
||||
virtual void format_context_end(const detail::log_entry_metadata& md,
|
||||
const std::string& ctx_name,
|
||||
fmt::memory_buffer& buffer) = 0;
|
||||
|
||||
/// This callback gets called at the beginning of a metric set formatting
|
||||
/// procedure.
|
||||
virtual void format_metric_set_begin(const std::string& set_name,
|
||||
unsigned size,
|
||||
unsigned level,
|
||||
fmt::memory_buffer& buffer) = 0;
|
||||
|
||||
/// This callback gets called at the beginning of a metric set formatting end.
|
||||
virtual void format_metric_set_end(const std::string& set_name,
|
||||
unsigned level,
|
||||
fmt::memory_buffer& buffer) = 0;
|
||||
|
||||
/// This callback gets called at the beginning of a metric list formatting
|
||||
/// procedure.
|
||||
virtual void format_list_begin(const std::string& list_name,
|
||||
unsigned size,
|
||||
unsigned level,
|
||||
fmt::memory_buffer& buffer) = 0;
|
||||
|
||||
/// This callback gets called at the end of a metric list formatting
|
||||
/// procedure.
|
||||
virtual void format_list_end(const std::string& list_name,
|
||||
unsigned level,
|
||||
fmt::memory_buffer& buffer) = 0;
|
||||
|
||||
/// This callback gets called for each metric.
|
||||
virtual void format_metric(const std::string& metric_name,
|
||||
const std::string& metric_value,
|
||||
const std::string& metric_units,
|
||||
metric_kind kind,
|
||||
unsigned level,
|
||||
fmt::memory_buffer& buffer) = 0;
|
||||
};
|
||||
|
||||
} // namespace srslog
|
||||
|
||||
#endif // SRSLOG_FORMATTER_H
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,150 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2020 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "srslte/common/enb_events.h"
|
||||
#include "srslte/srslog/context.h"
|
||||
#include "srslte/srslog/log_channel.h"
|
||||
|
||||
using namespace srsenb;
|
||||
|
||||
namespace {
|
||||
|
||||
/// Null object implementation that is used when no log channel is configured.
|
||||
class null_event_logger : public event_logger_interface
|
||||
{
|
||||
public:
|
||||
void log_rrc_connected(unsigned cause) override {}
|
||||
void log_rrc_disconnect(unsigned reason) override {}
|
||||
void log_s1_ctx_create(uint32_t mme_id, uint32_t enb_id, uint16_t rnti) override {}
|
||||
void log_s1_ctx_delete(uint32_t mme_id, uint32_t enb_id, uint16_t rnti) override {}
|
||||
void log_sector_start(uint32_t cc_idx, uint32_t pci, uint32_t cell_id) override {}
|
||||
void log_sector_stop(uint32_t cc_idx, uint32_t pci, uint32_t cell_id) override {}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
|
||||
/// Common metrics to all events.
|
||||
DECLARE_METRIC("type", metric_type_tag, std::string, "");
|
||||
DECLARE_METRIC("event_name", metric_event_name, std::string, "");
|
||||
|
||||
/// Context for sector start/stop.
|
||||
DECLARE_METRIC("pci", metric_pci, uint32_t, "");
|
||||
DECLARE_METRIC("cell_identity", metric_cell_identity, uint32_t, "");
|
||||
DECLARE_METRIC("sector_id", metric_sector_id, uint32_t, "");
|
||||
DECLARE_METRIC_SET("event_data", mset_sector_event, metric_pci, metric_cell_identity, metric_sector_id);
|
||||
using sector_event_t = srslog::build_context_type<metric_type_tag, metric_event_name, mset_sector_event>;
|
||||
|
||||
/// Context for RRC connect/disconnect.
|
||||
DECLARE_METRIC("cause", metric_cause, uint32_t, "");
|
||||
DECLARE_METRIC_SET("event_data", mset_rrc_event, metric_cause);
|
||||
using rrc_event_t = srslog::build_context_type<metric_type_tag, metric_event_name, mset_rrc_event>;
|
||||
|
||||
/// Context for S1 context create/delete.
|
||||
DECLARE_METRIC("mme_ue_s1ap_id", metric_ue_mme_id, uint32_t, "");
|
||||
DECLARE_METRIC("enb_ue_s1ap_id", metric_ue_enb_id, uint32_t, "");
|
||||
DECLARE_METRIC("rnti", metric_rnti, uint16_t, "");
|
||||
DECLARE_METRIC_SET("event_data", mset_s1apctx_event, metric_ue_mme_id, metric_ue_enb_id, metric_rnti);
|
||||
using s1apctx_event_t = srslog::build_context_type<metric_type_tag, metric_event_name, mset_s1apctx_event>;
|
||||
|
||||
/// Logs events into the configured log channel.
|
||||
class logging_event_logger : public event_logger_interface
|
||||
{
|
||||
public:
|
||||
explicit logging_event_logger(srslog::log_channel& c) : event_channel(c) {}
|
||||
|
||||
void log_rrc_connected(unsigned cause) override
|
||||
{
|
||||
rrc_event_t ctx("");
|
||||
|
||||
ctx.write<metric_type_tag>("event");
|
||||
ctx.write<metric_event_name>("rrc_connect");
|
||||
ctx.get<mset_rrc_event>().write<metric_cause>(cause);
|
||||
event_channel(ctx);
|
||||
}
|
||||
|
||||
void log_rrc_disconnect(unsigned reason) override
|
||||
{
|
||||
rrc_event_t ctx("");
|
||||
|
||||
ctx.write<metric_type_tag>("event");
|
||||
ctx.write<metric_event_name>("rrc_disconnect");
|
||||
ctx.get<mset_rrc_event>().write<metric_cause>(reason);
|
||||
event_channel(ctx);
|
||||
}
|
||||
|
||||
void log_s1_ctx_create(uint32_t mme_id, uint32_t enb_id, uint16_t rnti) override
|
||||
{
|
||||
s1apctx_event_t ctx("");
|
||||
|
||||
ctx.write<metric_type_tag>("event");
|
||||
ctx.write<metric_event_name>("s1_context_create");
|
||||
ctx.get<mset_s1apctx_event>().write<metric_ue_mme_id>(mme_id);
|
||||
ctx.get<mset_s1apctx_event>().write<metric_ue_enb_id>(enb_id);
|
||||
ctx.get<mset_s1apctx_event>().write<metric_rnti>(rnti);
|
||||
event_channel(ctx);
|
||||
}
|
||||
|
||||
void log_s1_ctx_delete(uint32_t mme_id, uint32_t enb_id, uint16_t rnti) override
|
||||
{
|
||||
s1apctx_event_t ctx("");
|
||||
|
||||
ctx.write<metric_type_tag>("event");
|
||||
ctx.write<metric_event_name>("s1_context_delete");
|
||||
ctx.get<mset_s1apctx_event>().write<metric_ue_mme_id>(mme_id);
|
||||
ctx.get<mset_s1apctx_event>().write<metric_ue_enb_id>(enb_id);
|
||||
ctx.get<mset_s1apctx_event>().write<metric_rnti>(rnti);
|
||||
event_channel(ctx);
|
||||
}
|
||||
|
||||
void log_sector_start(uint32_t cc_idx, uint32_t pci, uint32_t cell_id) override
|
||||
{
|
||||
sector_event_t ctx("");
|
||||
|
||||
ctx.write<metric_type_tag>("event");
|
||||
ctx.write<metric_event_name>("sector_start");
|
||||
ctx.get<mset_sector_event>().write<metric_pci>(pci);
|
||||
ctx.get<mset_sector_event>().write<metric_cell_identity>(cell_id);
|
||||
ctx.get<mset_sector_event>().write<metric_sector_id>(cc_idx);
|
||||
event_channel(ctx);
|
||||
}
|
||||
|
||||
void log_sector_stop(uint32_t cc_idx, uint32_t pci, uint32_t cell_id) override
|
||||
{
|
||||
sector_event_t ctx("");
|
||||
|
||||
ctx.write<metric_type_tag>("event");
|
||||
ctx.write<metric_event_name>("sector_stop");
|
||||
ctx.get<mset_sector_event>().write<metric_pci>(pci);
|
||||
ctx.get<mset_sector_event>().write<metric_cell_identity>(cell_id);
|
||||
ctx.get<mset_sector_event>().write<metric_sector_id>(cc_idx);
|
||||
event_channel(ctx);
|
||||
}
|
||||
|
||||
private:
|
||||
srslog::log_channel& event_channel;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<event_logger_interface> event_logger::pimpl = std::unique_ptr<null_event_logger>(new null_event_logger);
|
||||
|
||||
event_logger_interface& event_logger::get()
|
||||
{
|
||||
return *pimpl;
|
||||
}
|
||||
|
||||
void event_logger::configure(srslog::log_channel& c)
|
||||
{
|
||||
pimpl = std::unique_ptr<logging_event_logger>(new logging_event_logger(c));
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/**
|
||||
*
|
||||
* section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2020 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "srslte/phy/fec/polar/polar_interleaver.h"
|
||||
#include "srslte/phy/utils/vector.h"
|
||||
#include <memory.h>
|
||||
#include <stddef.h>
|
||||
|
||||
// Table 5.3.1.1-1: Interleaving pattern
|
||||
static const uint16_t polar_interleaver_pattern[SRSLTE_POLAR_INTERLEAVER_K_MAX_IL] = {
|
||||
0, 2, 4, 7, 9, 14, 19, 20, 24, 25, 26, 28, 31, 34, 42, 45, 49, 50, 51, 53, 54,
|
||||
56, 58, 59, 61, 62, 65, 66, 67, 69, 70, 71, 72, 76, 77, 81, 82, 83, 87, 88, 89, 91,
|
||||
93, 95, 98, 101, 104, 106, 108, 110, 111, 113, 115, 118, 119, 120, 122, 123, 126, 127, 129, 132, 134,
|
||||
138, 139, 140, 1, 3, 5, 8, 10, 15, 21, 27, 29, 32, 35, 43, 46, 52, 55, 57, 60, 63,
|
||||
68, 73, 78, 84, 90, 92, 94, 96, 99, 102, 105, 107, 109, 112, 114, 116, 121, 124, 128, 130, 133,
|
||||
135, 141, 6, 11, 16, 22, 30, 33, 36, 44, 47, 64, 74, 79, 85, 97, 100, 103, 117, 125, 131,
|
||||
136, 142, 12, 17, 23, 37, 48, 75, 80, 86, 137, 143, 13, 18, 38, 144, 39, 145, 40, 146, 41,
|
||||
147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163};
|
||||
|
||||
void srslte_polar_interleaver_run(const void* in, void* out, uint32_t S, uint32_t K, bool dir)
|
||||
{
|
||||
if (in == NULL || out == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
const uint8_t* in_ptr = (const uint8_t*)in;
|
||||
uint8_t* out_ptr = (uint8_t*)out;
|
||||
|
||||
uint32_t k = 0;
|
||||
for (uint32_t m = 0; m < SRSLTE_POLAR_INTERLEAVER_K_MAX_IL; m++) {
|
||||
if (polar_interleaver_pattern[m] >= SRSLTE_POLAR_INTERLEAVER_K_MAX_IL - K) {
|
||||
uint32_t pi_k = polar_interleaver_pattern[m] - (SRSLTE_POLAR_INTERLEAVER_K_MAX_IL - K);
|
||||
if (dir) {
|
||||
memcpy(out_ptr + S * k, in_ptr + S * pi_k, S);
|
||||
} else {
|
||||
memcpy(out_ptr + S * pi_k, in_ptr + S * k, S);
|
||||
}
|
||||
k++;
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,50 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2020 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "polar_interleaver_gold.h"
|
||||
#include "srslte/common/test_common.h"
|
||||
#include "srslte/phy/fec/polar/polar_interleaver.h"
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
uint32_t idx = 0;
|
||||
while (polar_interleaver_gold[idx].K) {
|
||||
uint32_t K = polar_interleaver_gold[idx].K;
|
||||
|
||||
// Create indexes in order
|
||||
uint16_t indexes_in[SRSLTE_POLAR_INTERLEAVER_K_MAX_IL];
|
||||
for (uint16_t i = 0; i < (uint16_t)K; i++) {
|
||||
indexes_in[i] = i;
|
||||
}
|
||||
|
||||
// Run interleaver forward
|
||||
uint16_t indexes_out[SRSLTE_POLAR_INTERLEAVER_K_MAX_IL];
|
||||
srslte_polar_interleaver_run_u16(indexes_in, indexes_out, K, true);
|
||||
|
||||
// Check indexes
|
||||
for (uint32_t i = 0; i < K; i++) {
|
||||
TESTASSERT(polar_interleaver_gold[idx].indexes[i] == indexes_out[i]);
|
||||
}
|
||||
|
||||
// Run interleaver backwards
|
||||
srslte_polar_interleaver_run_u16(indexes_out, indexes_in, K, false);
|
||||
|
||||
// Check indexes
|
||||
for (uint16_t i = 0; i < (uint16_t)K; i++) {
|
||||
TESTASSERT(indexes_in[i] == i);
|
||||
}
|
||||
|
||||
idx++;
|
||||
}
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
@ -1,96 +0,0 @@
|
||||
/**
|
||||
* 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,13 @@
|
||||
#
|
||||
# Copyright 2013-2020 Software Radio Systems Limited
|
||||
#
|
||||
# By using this file, you agree to the terms and conditions set
|
||||
# forth in the LICENSE file which can be found at the top level of
|
||||
# the distribution.
|
||||
#
|
||||
|
||||
set(SOURCES
|
||||
json_formatter.cpp
|
||||
text_formatter.cpp)
|
||||
|
||||
add_library(formatters STATIC ${SOURCES})
|
@ -0,0 +1,149 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2020 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "json_formatter.h"
|
||||
#include "srslte/srslog/detail/log_entry_metadata.h"
|
||||
|
||||
using namespace srslog;
|
||||
|
||||
std::unique_ptr<log_formatter> json_formatter::clone() const
|
||||
{
|
||||
return std::unique_ptr<log_formatter>(new json_formatter);
|
||||
}
|
||||
|
||||
void json_formatter::format(detail::log_entry_metadata&& metadata,
|
||||
fmt::memory_buffer& buffer)
|
||||
{
|
||||
fmt::format_to(buffer,
|
||||
"{{\n"
|
||||
" \"log_entry\": \"{}\"",
|
||||
fmt::vsprintf(metadata.fmtstring, std::move(metadata.store)));
|
||||
|
||||
if (!metadata.hex_dump.empty()) {
|
||||
fmt::format_to(
|
||||
buffer,
|
||||
",\n \"hex_dump\": \"{:02x}\"",
|
||||
fmt::join(metadata.hex_dump.cbegin(), metadata.hex_dump.cend(), " "));
|
||||
}
|
||||
|
||||
fmt::format_to(buffer, "\n}}\n");
|
||||
}
|
||||
|
||||
void json_formatter::format_context_begin(const detail::log_entry_metadata& md,
|
||||
const std::string& ctx_name,
|
||||
unsigned size,
|
||||
fmt::memory_buffer& buffer)
|
||||
{
|
||||
assert(scope_stack.empty() && "Stack should be empty");
|
||||
assert(nest_level == 0 && "Nesting level should be 0");
|
||||
|
||||
fmt::format_to(buffer, "{{\n");
|
||||
push_scope(size);
|
||||
|
||||
if (!md.fmtstring.empty()) {
|
||||
fmt::format_to(buffer,
|
||||
" \"log_entry\": \"{}\",\n",
|
||||
fmt::vsprintf(md.fmtstring, std::move(md.store)));
|
||||
}
|
||||
}
|
||||
|
||||
void json_formatter::format_context_end(const detail::log_entry_metadata& md,
|
||||
const std::string& ctx_name,
|
||||
fmt::memory_buffer& buffer)
|
||||
{
|
||||
pop_scope();
|
||||
fmt::format_to(buffer, "}}\n");
|
||||
|
||||
assert(scope_stack.empty() && "Stack should be empty");
|
||||
assert(nest_level == 0 && "Nesting level should be 0");
|
||||
}
|
||||
|
||||
void json_formatter::format_metric_set_begin(const std::string& set_name,
|
||||
unsigned size,
|
||||
unsigned level,
|
||||
fmt::memory_buffer& buffer)
|
||||
{
|
||||
// Arrays in JSON require an additional nesting level before inserting the
|
||||
// object.
|
||||
// array: [
|
||||
// {
|
||||
// "obj: {}
|
||||
// }
|
||||
// ]
|
||||
if (in_list_scope()) {
|
||||
fmt::format_to(buffer, "{: <{}}{{\n", ' ', indents(level));
|
||||
increment_nest_level();
|
||||
}
|
||||
|
||||
consume_element();
|
||||
|
||||
fmt::format_to(buffer, "{: <{}}\"{}\": {{\n", ' ', indents(level), set_name);
|
||||
push_scope(size);
|
||||
}
|
||||
|
||||
void json_formatter::format_metric_set_end(const std::string& set_name,
|
||||
unsigned level,
|
||||
fmt::memory_buffer& buffer)
|
||||
{
|
||||
pop_scope();
|
||||
fmt::format_to(buffer,
|
||||
"{: <{}}}}{}\n",
|
||||
' ',
|
||||
indents(level),
|
||||
needs_comma() && !in_list_scope() ? "," : "");
|
||||
|
||||
if (in_list_scope()) {
|
||||
decrement_nest_level();
|
||||
fmt::format_to(
|
||||
buffer, "{: <{}}}}{}\n", ' ', indents(level), needs_comma() ? "," : "");
|
||||
}
|
||||
}
|
||||
|
||||
void json_formatter::format_metric(const std::string& metric_name,
|
||||
const std::string& metric_value,
|
||||
const std::string& metric_units,
|
||||
metric_kind kind,
|
||||
unsigned level,
|
||||
fmt::memory_buffer& buffer)
|
||||
{
|
||||
consume_element();
|
||||
|
||||
fmt::format_to(buffer,
|
||||
"{: <{}}\"{}\": {}{}{}{}\n",
|
||||
' ',
|
||||
indents(level),
|
||||
metric_name,
|
||||
kind == metric_kind::string ? "\"" : "",
|
||||
metric_value,
|
||||
kind == metric_kind::string ? "\"" : "",
|
||||
needs_comma() ? "," : "");
|
||||
}
|
||||
|
||||
void json_formatter::format_list_begin(const std::string& list_name,
|
||||
unsigned size,
|
||||
unsigned level,
|
||||
fmt::memory_buffer& buffer)
|
||||
{
|
||||
consume_element();
|
||||
|
||||
fmt::format_to(buffer, "{: <{}}\"{}\": [\n", ' ', indents(level), list_name);
|
||||
push_list_scope(size);
|
||||
}
|
||||
|
||||
void json_formatter::format_list_end(const std::string& list_name,
|
||||
unsigned level,
|
||||
fmt::memory_buffer& buffer)
|
||||
{
|
||||
pop_scope();
|
||||
fmt::format_to(
|
||||
buffer, "{: <{}}]{}\n", ' ', indents(level), needs_comma() ? "," : "");
|
||||
}
|
@ -0,0 +1,137 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2020 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSLOG_JSON_FORMATTER_H
|
||||
#define SRSLOG_JSON_FORMATTER_H
|
||||
|
||||
#include "srslte/srslog/formatter.h"
|
||||
|
||||
namespace srslog {
|
||||
|
||||
/// JSON formatter class implementation.
|
||||
/// Formats each log entry and context into its own JSON object making the
|
||||
/// formatter stateless so that new entries do not depend on the state of
|
||||
/// previous ones. The output is ready for JSON streaming following the
|
||||
/// "Concatenated JSON" style.
|
||||
class json_formatter : public log_formatter
|
||||
{
|
||||
public:
|
||||
json_formatter() { scope_stack.reserve(16); }
|
||||
|
||||
std::unique_ptr<log_formatter> clone() const override;
|
||||
|
||||
void format(detail::log_entry_metadata&& metadata,
|
||||
fmt::memory_buffer& buffer) override;
|
||||
|
||||
private:
|
||||
void format_context_begin(const detail::log_entry_metadata& md,
|
||||
const std::string& ctx_name,
|
||||
unsigned size,
|
||||
fmt::memory_buffer& buffer) override;
|
||||
|
||||
void format_context_end(const detail::log_entry_metadata& md,
|
||||
const std::string& ctx_name,
|
||||
fmt::memory_buffer& buffer) override;
|
||||
|
||||
void format_metric_set_begin(const std::string& set_name,
|
||||
unsigned size,
|
||||
unsigned level,
|
||||
fmt::memory_buffer& buffer) override;
|
||||
|
||||
void format_metric_set_end(const std::string& set_name,
|
||||
unsigned level,
|
||||
fmt::memory_buffer& buffer) override;
|
||||
|
||||
void format_list_begin(const std::string& list_name,
|
||||
unsigned size,
|
||||
unsigned level,
|
||||
fmt::memory_buffer& buffer) override;
|
||||
|
||||
void format_list_end(const std::string& list_name,
|
||||
unsigned level,
|
||||
fmt::memory_buffer& buffer) override;
|
||||
|
||||
void format_metric(const std::string& metric_name,
|
||||
const std::string& metric_value,
|
||||
const std::string& metric_units,
|
||||
metric_kind kind,
|
||||
unsigned level,
|
||||
fmt::memory_buffer& buffer) override;
|
||||
|
||||
/// Pushes a new entry in the scope stack.
|
||||
void push_scope(unsigned size) { scope_stack.emplace_back(size, false); }
|
||||
|
||||
/// Pushes a new list entry in the scope stack.
|
||||
void push_list_scope(unsigned size) { scope_stack.emplace_back(size, true); }
|
||||
|
||||
/// Pops the topmost entry in the scope stack.
|
||||
void pop_scope()
|
||||
{
|
||||
assert(!scope_stack.empty() && "Popping scope in empty stack");
|
||||
scope_stack.pop_back();
|
||||
}
|
||||
|
||||
/// Consumes an element in the current scope.
|
||||
void consume_element()
|
||||
{
|
||||
assert(!scope_stack.empty() && "Consuming element in void scope");
|
||||
assert(scope_stack.back().size && "No more elements to consume");
|
||||
--scope_stack.back().size;
|
||||
}
|
||||
|
||||
/// Returns true if the current element needs a comma.
|
||||
bool needs_comma() const
|
||||
{
|
||||
assert(!scope_stack.empty() && "No scope exists");
|
||||
return scope_stack.back().size;
|
||||
}
|
||||
|
||||
/// Returns true if the current scope is a list.
|
||||
bool in_list_scope() const
|
||||
{
|
||||
assert(!scope_stack.empty() && "No scope exists");
|
||||
return scope_stack.back().inside_list;
|
||||
}
|
||||
|
||||
/// Increments the nesting level by one.
|
||||
void increment_nest_level() { ++nest_level; }
|
||||
|
||||
/// Decrements the nesting level by one.
|
||||
void decrement_nest_level()
|
||||
{
|
||||
assert(nest_level && "Expected the nesting level to greater than 0");
|
||||
--nest_level;
|
||||
}
|
||||
|
||||
/// Return the number of space chars to indent the specified level.
|
||||
unsigned indents(unsigned level) const { return (nest_level + level) * 2; }
|
||||
|
||||
private:
|
||||
/// Keeps track of some information about a JSON scope.
|
||||
struct scope {
|
||||
scope(unsigned size, bool inside_list) :
|
||||
size(size), inside_list(inside_list)
|
||||
{}
|
||||
/// Number of elements this scope holds.
|
||||
unsigned size;
|
||||
/// If true, indicates this scope belongs to a list.
|
||||
const bool inside_list;
|
||||
};
|
||||
|
||||
private:
|
||||
unsigned nest_level = 0;
|
||||
std::vector<scope> scope_stack;
|
||||
};
|
||||
|
||||
} // namespace srslog
|
||||
|
||||
#endif // SRSLOG_JSON_FORMATTER_H
|
@ -0,0 +1,160 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2020 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "text_formatter.h"
|
||||
#include "srslte/srslog/bundled/fmt/chrono.h"
|
||||
#include "srslte/srslog/detail/log_entry_metadata.h"
|
||||
|
||||
using namespace srslog;
|
||||
|
||||
std::unique_ptr<log_formatter> text_formatter::clone() const
|
||||
{
|
||||
return std::unique_ptr<log_formatter>(new text_formatter(*this));
|
||||
}
|
||||
|
||||
/// Formats into a hex dump a range of elements, storing the result in the input
|
||||
/// buffer.
|
||||
static 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);
|
||||
}
|
||||
}
|
||||
|
||||
/// Format the log metadata into the input buffer.
|
||||
static void format_metadata(const detail::log_entry_metadata& metadata,
|
||||
fmt::memory_buffer& buffer)
|
||||
{
|
||||
// Time stamp data preparation.
|
||||
std::tm current_time =
|
||||
fmt::gmtime(std::chrono::high_resolution_clock::to_time_t(metadata.tp));
|
||||
auto us_fraction = std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
metadata.tp.time_since_epoch())
|
||||
.count() %
|
||||
1000000u;
|
||||
fmt::format_to(buffer, "{:%H:%M:%S}.{:06} ", current_time, us_fraction);
|
||||
|
||||
// Format optional fields if present.
|
||||
if (!metadata.log_name.empty()) {
|
||||
fmt::format_to(buffer, "[{: <4.4}] ", metadata.log_name);
|
||||
}
|
||||
if (metadata.log_tag != '\0') {
|
||||
fmt::format_to(buffer, "[{}] ", metadata.log_tag);
|
||||
}
|
||||
if (metadata.context.enabled) {
|
||||
fmt::format_to(buffer, "[{:5}] ", metadata.context.value);
|
||||
}
|
||||
}
|
||||
|
||||
void text_formatter::format(detail::log_entry_metadata&& metadata,
|
||||
fmt::memory_buffer& buffer)
|
||||
{
|
||||
// Prefix first.
|
||||
format_metadata(metadata, buffer);
|
||||
|
||||
// Message formatting.
|
||||
fmt::format_to(buffer,
|
||||
"{}\n",
|
||||
fmt::vsprintf(metadata.fmtstring, std::move(metadata.store)));
|
||||
|
||||
// Optional hex dump formatting.
|
||||
format_hex_dump(metadata.hex_dump, buffer);
|
||||
}
|
||||
|
||||
void text_formatter::format_context_begin(const detail::log_entry_metadata& md,
|
||||
const std::string& ctx_name,
|
||||
unsigned size,
|
||||
fmt::memory_buffer& buffer)
|
||||
{
|
||||
do_one_line_ctx_format = !md.fmtstring.empty();
|
||||
|
||||
format_metadata(md, buffer);
|
||||
if (do_one_line_ctx_format) {
|
||||
fmt::format_to(buffer, "[");
|
||||
return;
|
||||
}
|
||||
fmt::format_to(buffer, "Context dump for \"{}\"\n", ctx_name);
|
||||
}
|
||||
|
||||
void text_formatter::format_context_end(const detail::log_entry_metadata& md,
|
||||
const std::string& ctx_name,
|
||||
fmt::memory_buffer& buffer)
|
||||
{
|
||||
if (do_one_line_ctx_format) {
|
||||
fmt::format_to(buffer, "]: {}\n", fmt::vsprintf(md.fmtstring, md.store));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void text_formatter::format_metric_set_begin(const std::string& set_name,
|
||||
unsigned size,
|
||||
unsigned level,
|
||||
fmt::memory_buffer& buffer)
|
||||
{
|
||||
/*if (do_one_line_ctx_format) {
|
||||
fmt::format_to(buffer, "{}", is_first ? "[" : " [");
|
||||
return;
|
||||
}
|
||||
fmt::format_to(buffer, " {}\n", set_name);*/
|
||||
}
|
||||
|
||||
void text_formatter::format_metric_set_end(const std::string& set_name,
|
||||
unsigned level,
|
||||
fmt::memory_buffer& buffer)
|
||||
{
|
||||
if (do_one_line_ctx_format) {
|
||||
fmt::format_to(buffer, "]");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void text_formatter::format_metric(const std::string& metric_name,
|
||||
const std::string& metric_value,
|
||||
const std::string& metric_units,
|
||||
metric_kind kind,
|
||||
unsigned level,
|
||||
fmt::memory_buffer& buffer)
|
||||
{
|
||||
//:TODO: re-enable
|
||||
/*if (do_one_line_ctx_format) {
|
||||
fmt::format_to(buffer,
|
||||
"{}{}_{}: {}{}{}",
|
||||
ctx.is_first_metric ? "" : ", ",
|
||||
ctx.set_name,
|
||||
ctx.metric_name,
|
||||
ctx.metric_value,
|
||||
ctx.metric_units.empty() ? "" : " ",
|
||||
ctx.metric_units);
|
||||
return;
|
||||
}
|
||||
fmt::format_to(buffer,
|
||||
" {}: {}{}{}\n",
|
||||
ctx.metric_name,
|
||||
ctx.metric_value,
|
||||
ctx.metric_units.empty() ? "" : " ",
|
||||
ctx.metric_units);*/
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2020 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSLOG_TEXT_FORMATTER_H
|
||||
#define SRSLOG_TEXT_FORMATTER_H
|
||||
|
||||
#include "srslte/srslog/formatter.h"
|
||||
|
||||
namespace srslog {
|
||||
|
||||
/// Plain text formatter implementation class.
|
||||
//:TODO: this class needs refactoring to be compatible with multiple nesting of
|
||||
// metrics.
|
||||
class text_formatter : public log_formatter
|
||||
{
|
||||
public:
|
||||
std::unique_ptr<log_formatter> clone() const override;
|
||||
|
||||
void format(detail::log_entry_metadata&& metadata,
|
||||
fmt::memory_buffer& buffer) override;
|
||||
|
||||
private:
|
||||
void format_context_begin(const detail::log_entry_metadata& md,
|
||||
const std::string& ctx_name,
|
||||
unsigned size,
|
||||
fmt::memory_buffer& buffer) override;
|
||||
|
||||
void format_context_end(const detail::log_entry_metadata& md,
|
||||
const std::string& ctx_name,
|
||||
fmt::memory_buffer& buffer) override;
|
||||
|
||||
void format_metric_set_begin(const std::string& set_name,
|
||||
unsigned size,
|
||||
unsigned level,
|
||||
fmt::memory_buffer& buffer) override;
|
||||
|
||||
void format_metric_set_end(const std::string& set_name,
|
||||
unsigned level,
|
||||
fmt::memory_buffer& buffer) override;
|
||||
|
||||
void format_list_begin(const std::string& list_name,
|
||||
unsigned size,
|
||||
unsigned level,
|
||||
fmt::memory_buffer& buffer) override
|
||||
{
|
||||
//:TODO: implement me
|
||||
}
|
||||
|
||||
void format_list_end(const std::string& list_name,
|
||||
unsigned level,
|
||||
fmt::memory_buffer& buffer) override
|
||||
{
|
||||
//:TODO: implement me
|
||||
}
|
||||
|
||||
void format_metric(const std::string& metric_name,
|
||||
const std::string& metric_value,
|
||||
const std::string& metric_units,
|
||||
metric_kind kind,
|
||||
unsigned level,
|
||||
fmt::memory_buffer& buffer) override;
|
||||
|
||||
private:
|
||||
/// Flags that the formatting should take place into a single line.
|
||||
bool do_one_line_ctx_format = false;
|
||||
};
|
||||
|
||||
} // namespace srslog
|
||||
|
||||
#endif // SRSLOG_TEXT_FORMATTER_H
|
@ -1,123 +0,0 @@
|
||||
/**
|
||||
* 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
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue