ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

osquery Logger 插件开发指南:从 logString 到自定义日志后端

osquery Logger 插件开发指南:从 logString 到自定义日志后端 观测代理网络安全【免费下载链接】osquerySQL powered operating system instrumentation, monitoring, and analytics.项目地址https://gitcode.com/gh_mirrors/os/osquery点击查看免费下载osquery 内置的日志插件logger plugin是连接osqueryd查询结果与外部日志系统的核心扩展点。本文基于官方开发文档 logger-plugins.md 展开结合仓库源码讲解如何实现一个自定义 Logger 插件、如何注册并在启动时启用它同时深入LoggerPlugin基类与内部日志流水线的实现原理帮助你掌握把 osquery 查询结果和状态日志接入 Scribe、Flume、Splunk、Kafka、TLS 端点或自研系统的完整方法。osquery 为什么需要可插拔的日志层osqueryd会按照配置调度查询并收集变更结果。这些结果最终都要落盘或转发到某个日志系统而不同企业的日志基础设施各不相同有人用 Scribe、有人用 Flume、有人直接写文件。为此 osquery 将日志输出抽象为独立的logger 插件机制只需要实现一个接收字符串参数的 C 函数就能把 osquery 产生的日志接入任意上游日志服务。关于osqueryd如何调度查询、如何从配置加载信息请参阅 配置部署指南。本文只聚焦于日志插件本身的开发与原理。从仓库结构看logger 插件体系的代码分布在三处插件基类与状态日志数据结构osquery/core/plugins/logger.h日志核心逻辑注册表、缓冲 sink、分发入口osquery/logger/logger.cpp内置插件实现plugins/logger/包括 filesystem、stdout、syslog、tls、buffered、kafka、aws firehose/kinesis、windows_event_log 等最小实现一个输出到 glog 的 Logger 插件官方文档给出了一个「刻意简化」的示例插件——把每条日志写到 glog 的 INFO 行。以下是完整代码#include osquery/logger/logger.h #include glog/logging.h namespace osquery { class GlogLoggerPlugin : public LoggerPlugin { public: Status logString(const std::string message) { LOG(INFO) message; return Status(0, OK); } virtual ~GlogLoggerPlugin() {} }; REGISTER(GlogLoggerPlugin, logger, glog); }这段代码的核心要点继承LoggerPlugin基类定义于 osquery/core/plugins/logger.h并实现纯虚函数logString当守护进程发现查询调度发生变化时会把变更细节序列化为 JSON然后调用当前激活 logger 插件的logString方法通过REGISTER(GlogLoggerPlugin, logger, glog)将插件注册到名为logger的插件注册表注册名glog将作为后续--logger_plugin参数使用的标识符。基类中的其他可覆写方法虽然只需实现logString就能工作但LoggerPlugin基类还定义了若干可选虚方法用于支持更复杂的日志场景见 osquery/core/plugins/logger.h方法作用默认行为logString(const std::string)记录一条序列化后的日志字符串纯虚必须实现—logStatus(const std::vectorStatusLogLine)批量接收 glog 状态日志INFO/WARNING/ERROR返回Status(1, Not enabled)即默认不启用logSnapshot(const std::string)单独处理快照查询snapshot结果直接转发给logStringlogEvent(const std::string)每个事件订阅者发布的事件直接转发给 logger绕过数据库缓冲返回Status(1, Not enabled)logStringBatch(const std::string)接收一批事件JSON 数组并逐条调用logString基类提供默认实现逐条分发usesLogStatus()是否启用 glog 状态日志转发falseusesLogEvent()是否启用事件直通转发falseinit(const std::string, const std::vectorStatusLogLine)进程启动后初始化接收启动早期产生的缓冲状态日志纯虚—其中StatusLogLine是状态日志的中间结构见 osquery/core/plugins/logger.h包含严重级别StatusLogSeverityO_INFO/O_WARNING/O_ERROR/O_FATAL、文件名、行号、消息、日历时间、UNIX 时间与主机标识符。注册插件REGISTER 宏与 logger 注册表REGISTER(GlogLoggerPlugin, logger, glog)本质上是把插件实例注册进 osquery 的插件注册表。日志注册表在 osquery/logger/logger.cpp 中通过CREATE_REGISTRY(LoggerPlugin, logger)创建所有 logger 插件共享这一个logger注册域。仓库中所有内置插件都遵循同样的注册模式例如文件系统日志插件的注册位于 plugins/logger/filesystem_logger.hREGISTER(FilesystemLoggerPlugin, logger, filesystem);filesystem同时也是--logger_plugin的默认值见 osquery/logger/logger.cpp 的CLI_FLAG(string, logger_plugin, filesystem, Logger plugin name)。启用插件--logger_plugin 参数插件编译链接进osqueryd后启动时通过--logger_plugin指定要激活的插件参数值必须与REGISTER中使用的字符串标识符一致osqueryd --logger_pluginglog使用系统默认的 filesystem 插件时该参数可以省略。此外--logger_plugin还支持用逗号分隔同时激活多个插件initLogger内部会逐个初始化并收集每个插件的特性位见 osquery/logger/logger.cpposqueryd --logger_pluginfilesystem,tls编译链接把插件源文件加入构建官方文档要求把插件源文件加入osquery/plugins/logger/CMakeLists.txt以便编译链接。在当前的仓库布局中该构建文件位于 plugins/logger/CMakeLists.txt其内部通过generatePluginsLogger*系列函数为每个插件生成独立的库目标例如generatePluginsLoggerFilesystemlogger编译filesystem_logger.cpp并链接osquery_core、osquery_filesystem、thirdparty_glog等依赖plugins/logger/CMakeLists.txtgeneratePluginsLoggerTlslogger编译tls_logger.cpp链接 TLS 传输、JSON 序列化与 buffered 插件plugins/logger/CMakeLists.txt。自定义插件可以参照上述函数为目标添加源文件与链接依赖需要注册add_test时也可参照现有测试目标写法如plugins_logger_tests_filesystemloggertests-test。内置插件一览现成的参考实现动手写插件前先看看仓库内置插件的设计它们本身就是最好的范本目录plugins/logger/插件注册名实现文件说明filesystemfilesystemfilesystem_logger.cpp默认插件结果、快照与状态日志写入不同文件stdoutstdoutstdout.cpp结果打印到 stdout状态日志带 severity/location 前缀syslogsyslogsyslog_logger.cppPOSIX 平台将日志写入系统 syslogtlstlstls_logger.cpp通过 TLS 端点上送日志带缓冲与重试bufferedbufferedbuffered.cpp带缓冲、重试与背压的日志转发器基类kafkakafkakafka_producer.cpp将日志投递到 Kafkaaws_firehose / aws_kinesis—aws_firehose.cpp、aws_kinesis.cpp由OSQUERY_BUILD_AWS控制构建的 AWS 日志通道以 stdout 插件为例plugins/logger/stdout.cpp它同时实现了logString、logStatus和init并在init中关闭 glog 默认的 stderr 输出、把启动早期缓冲的状态日志立即转储Status StdoutLoggerPlugin::logString(const std::string s) { std::cout s std::endl; return Status(); } void StdoutLoggerPlugin::init(const std::string name, const std::vectorStatusLogLine log) { // Stop the internal Glog facilities. FLAGS_alsologtostderr false; FLAGS_logtostderr false; FLAGS_stderrthreshold 5; // Now funnel the intermediate status logs provided to init. logStatus(log); }TLS 插件则是更复杂的参考tls_logger.h 中TLSLoggerPlugin覆写了usesLogStatus()返回true表示接管 glog 状态日志、setUp、configure与logStatus并借助TLSLogForwarder继承BufferedLogForwarder在 Dispatcher 线程中异步缓冲上送。深入原理一条日志如何到达你的 logString自定义插件的logString只是流水线的终点。理解整条调用链有助于判断何时需要覆写logStatus/logEvent/logSnapshot。查询结果日志的序列化与分发调度结果differential 结果与快照结果分别走logQueryLogItem与logSnapshotQuery见 osquery/logger/logger.cpp。以查询日志为例其流程为检查FLAGS_disable_logging若禁用则直接返回成功若启用FLAGS_enable_numeric_monitoring记录query.total.count监控指标根据FLAGS_logger_event_type默认true见 osquery/logger/logger.cpp决定将每条变更逐条序列化为事件 JSON还是整条结果序列化为单个 JSON逐条调用logString(json, event, receiver)。logString的重载实现osquery/logger/logger.cpp会遍历以逗号分隔的接收者列表对注册在核心进程内的插件直接dynamic_pointer_castLoggerPlugin后调用logString对扩展进程提供的插件则通过注册表的PluginRequest路由{{string, message}, {category, category}}调用。这意味着外部扩展也可以提供 logger 插件且调用方无需区分。状态日志的缓冲与转发BufferedLogSinkglog 状态日志INFO/WARNING/ERROR不直接进入logString而是由BufferedLogSinkosquery/logger/logger.cpp这个自定义google::LogSink统一收集进程启动早期glog 日志先被缓冲在内存队列logs_中当激活插件的init返回成功、且其usesLogStatus()特性位为真时对应LoggerFeatures::LOGGER_FEATURE_LOGSTATUS见 osquery/core/plugins/logger.hsink 会把该插件加入转发列表并开启转发守护进程每 3 秒通过relayStatusLogs把缓冲的状态日志序列化为 JSON字段s/f/i/m/h/c/u分别对应 severity、filename、line、message、host identifier、calendar time、unix time再批量调用插件的logStatus见 osquery/logger/logger.cpp。这解释了为什么filesystem插件在init中返回失败它让 glog 继续直接写文件而不是转发给logStatus见 plugins/logger/filesystem_logger.h 的注释。事件直通LOGGER_FEATURE_LOGEVENT如果插件usesLogEvent()返回trueinitLogger会把它注册为事件转发器EventFactory::addForwarder(logger)见 osquery/logger/logger.cpp。此后事件订阅者发布的事件会直接送达插件的logEvent跳过数据库缓冲层——适合对实时性要求高、或希望减少磁盘写放大场景的插件。编写插件时的关键决策清单综合以上源码分析开发一个生产可用的 logger 插件时建议依次确认logString是唯一必须实现的方法结果日志与默认的 snapshot 日志都会汇聚到这里返回Status(0, OK)表示成功需要状态日志INFO/WARNING/ERROR时实现logStatus与init并让usesLogStatus()返回true否则状态日志会继续由 glog 按默认方式处理需要处理大量快照数据时实现logSnapshot避免大数据量占用通用logString通道需要低延迟事件转发时实现logEvent并让usesLogEvent()返回true注册名保持唯一且稳定REGISTER(PluginClass, logger, name)中的name就是--logger_plugin使用的标识符接入构建在当前仓库中把源文件接入 plugins/logger/CMakeLists.txt参照现有generatePluginsLogger*函数组织编译目标与链接依赖。验证与测试仓库为每个内置插件都配备了单元测试可作为验证插件行为、理解插件契约的补充材料目录plugins/logger/tests/filesystem_logger_tests.cpp验证结果、快照与状态日志分别写入预期文件tls_logger_tests.cpp验证 TLS 上送、重试与缓冲buffered_tests.cpp验证缓冲与背压逻辑kafka_producer_tests.cpp 与 syslog_logger_tests.cpp分别验证 Kafka 投递与 syslog 输出。编写自定义插件后可仿照这些测试为目标注册add_test确保logString对 JSON 输入、状态日志批量输入以及异常输入如空字符串、超大消息的行为符合预期。小结osquery 的 logger 插件机制把「日志往哪送」完全交给了开发者实现一个logString即可接入任意日志系统覆写logStatus、logEvent、logSnapshot则可以精细控制状态日志、事件与快照的流向。结合 osquery/core/plugins/logger.h 的基类定义、osquery/logger/logger.cpp 的缓冲与分发逻辑以及 plugins/logger/ 下各内置插件的实现你可以在不修改 osquery 核心代码的前提下把查询结果稳定地接入自有的日志基础设施。赞分享观测代理网络安全【免费下载链接】osquerySQL powered operating system instrumentation, monitoring, and analytics.项目地址https://gitcode.com/gh_mirrors/os/osquery点击查看免费下载相关推荐osquery 配置插件开发指南从 filesystem 到自定义 ConfigPluginosquery 配置插件开发指南从 filesystem 到自定义 ConfigPlugin 配置分发是 osquery 部署中最具挑战性的环节之一默认情况观测代理网络安全什么是 tf-summarize?Terraform Plan 摘要神器一篇文章完全解读什么是 tf summarize?Terraform Plan 摘要神器一篇文章完全解读 每次运行 terraform plan 输出动辄几百上千行新增、修PaddleOCR 日志系统配置指南从集中式 logger 到自定义日志输出PaddleOCR 日志系统配置指南从集中式 logger 到自定义日志输出 paddleocr Python 包内置了一套基于标准库 logging 的集中人工智能计算机视觉深度学习上一篇get-shit-done 的 Continue-Here 模板跨会话无缝续作的状态交接机制实战下一篇终极Go Validator条件性字段验证从入门到精通的完整指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表