boost ::日志 - 使用库/插件内的独立严重性级别



这是我问的另一个问题(在此)的一种后续措施,我知道在其中,我知道在多个水槽中使用相同的后端不是安全的方法。

我试图获得的是使用它们从应用程序中"将"库/插件内的严重性级别"解除",同时能够将不同的日志写入相同的输出(愿意是Stdout,或者更有可能,更有可能,文件或远程记录器);出于以下原因,这是:

  1. 我不想将我的库/插件内的严重性级别与使用它们的应用程序的严重性级别联系在一起,因为使用库/插件的一个应用程序中的严重性级别(无论出于何种原因)列表的更改(无论出于何种原因)会导致将使用新的严重性"更新"的库,以及作为使用库/插件的所有其他应用程序中的库
  2. 我希望能够使用库特定的严重性级别(对于在日志中正确显示的时间应提供给水槽格式化器 - 因此我需要使用不同的水槽)

哪种是获得此信息的最佳方法?

一些事后的想法:根据安德烈(Andrey)对我以前的问题的答复,"问题"是后端没有同步以从多个来源(接收器)接收数据;因此,解决方案似乎是为了创建一个后端的同步版本(例如,将写入写入后端boost :: asio post)...
这是唯一的解决方案?


编辑/更新

我在安德烈(Andrey)的出色答复之后更新了这个问题,主要是为了完整:库/插件仅与内部开发的应用程序一起使用,因此假定我们将有一个常见的API我们可以定义定义日志结构和行为。
另外,大多数应用程序旨在主要运行"无人驾驶",即以最小的(如果不是null),用户/运行时交互,因此,基本想法是将日志级别设置在某些插件特定的配置文件中,请在启动时阅读(或在启动时读取(或设置将从应用程序中重新加载在特定的应用程序API命令上)。

首先,我想解决此前提:

要正确显示在日志中,应将其提供给水槽格式化器 - 因此我需要使用不同的水槽

您不需要不同的水槽即可过滤或格式化不同类型的严重程度。您的过滤器和格式化器必须处理这一点,而不是水槽本身。仅在需要多个日志目标时创建多个接收器。因此,要回答您的问题,您应该专注于设置过滤器和格式化器而不是下沉的协议。

确切的方法很难建议,因为您没有指定应用程序/插件系统的设计。我的意思是,应用程序和库必须共享一些常见的API,并且您设置的记录方式将取决于API所属的位置。严重程度,除其他外,必须是该API的一部分。例如:

  • 如果您是为特定应用程序编写插件(例如媒体播放器的插件),则该应用程序是定义插件API的应用程序,包括严重性级别,甚至可能是插件必须使用的属性名称。该应用程序使用API授权的属性配置了包括过滤器和格式的水槽,包括过滤器和格式化器,并且插件永远不会进行任何配置,只能发射日志记录。请注意,API可能包含一些允许彼此区分插件的属性(例如,频道名称),这些属性允许应用程序以不同的方式从不同的插件处理日志(例如,写入不同的文件)。

  • 如果您同时编写插件和应用程序来粘附一些常见的API,可能是由第三方定义的,则记录协议仍必须由该API定义。如果不是这样,那么您不能假设您没有编写的任何其他应用程序或插件都支持任何形式的记录,即使它完全使用boost.log。在这种情况下,每个插件和应用程序本身都必须独立处理记录,这是最坏的情况,因为插件和应用程序可能以无法预测的方式相互影响。也很难管理这样的系统,因为每个组件都必须由用户分开配置。

  • 如果您正在编写一个必须与多个库兼容的应用周围的方式。这可能包括在库中设置回调,拦截文件输出并在库的日志严重性级别和应用程序严重性级别之间进行翻译。如果库使用boost.log发射日志记录,则应记录其使用的属性,包括严重性级别,以便应用程序能够正确设置日志记录。

因此,为了采用一种方法或另一种方法,您应该首先确定应用程序和插件如何相互接口,以及它们共享的API以及API如何定义日志记录。最好的情况是当您定义API时,因此您还可以设置所需的记录约定。在这种情况下,尽管可能会有可能或典型的API允许的任意严重性水平,因为它显着复杂化了系统的实现和配置。

但是,如果由于某种原因,您确实需要支持任意的严重性级别,并且无法解决,则可以为库提供的API定义,这可以帮助应用程序设置过滤器和格式化。例如,每个插件都可以提供这样的API:

// Returns the filter that the plugin wishes to use for its records
boost::log::filter get_filter();
// The function extracts log severity from the log record
// and converts it to a string
typedef std::function<
    std::string(boost::log::record_view const&)
> severity_formatter;
// Returns the severity formatter, specific for the plugin
severity_formatter get_severity_formatter();

然后,该应用程序可以使用将使用此API的特殊过滤器。

struct plugin_filters
{
    std::shared_mutex mutex;
    // Plugin-specific filters
    std::vector< boost::log::filter > filters;
};
// Custom filter
bool check_plugin_filters(
    boost::log::attribute_value_set const& values,
    std::shared_ptr< plugin_filters > const& p)
{
    // Filters can be called in parallel, we need to synchronize
    std::shared_lock< std::shared_mutex > lock(p->mutex);
    for (auto const& f : p->filters)
    {
        // Call each of the plugin's filter and pass the record
        // if any of the filters passes
        if (f(values))
            return true;
    }
    // Suppress the record by default
    return false;
}
std::shared_ptr< plugin_filters > pf = std::make_shared< plugin_filters >();
// Set the filter
sink->set_filter(std::bind(&check_plugin_filters, std::placeholders::_1, pf));
// Add filters from plugins
std::unique_lock< std::shared_mutex > lock(pf->mutex);
pf->filters.push_back(plugin1->get_filter());
pf->filters.push_back(plugin2->get_filter());
...

和类似的格式:

struct plugin_formatters
{
    std::shared_mutex mutex;
    // Plugin-specific severity formatters
    std::vector< severity_formatter > severity_formatters;
};
// Custom severity formatter
std::string plugin_severity_formatter(
    boost::log::record_view const& rec,
    std::shared_ptr< plugin_formatters > const& p)
{
    std::shared_lock< std::shared_mutex > lock(p->mutex);
    for (auto const& f : p->severity_formatters)
    {
        // Call each of the plugin's formatter and return the result
        // if any of the formatters is able to extract the severity
        std::string str = f(rec);
        if (!str.empty())
            return str;
    }
    // By default return an empty string
    return std::string();
}
std::shared_ptr< plugin_formatters > pf =
    std::make_shared< plugin_formatters >();
// Set the formatter
sink->set_formatter(
    boost::log::expressions::stream << "["
        << boost::phoenix::bind(&plugin_severity_formatter,
               boost::log::expressions::record, pf)
        << "] " << boost::log::expressions::message);
// Add formatters from plugins
std::unique_lock< std::shared_mutex > lock(pf->mutex);
pf->severity_formatters.push_back(plugin1->get_severity_formatter());
pf->severity_formatters.push_back(plugin2->get_severity_formatter());
...
但是,请注意,至少关于过滤器,此方法存在缺陷,因为您允许插件定义过滤器。通常,应该是选择正在记录的记录的应用程序。为此,必须有一种将特定于图书馆的严重性级别转换为常见的方法,可能是由应用程序级别定义的。

最新更新