pluggit/monitoring

监控抽象层

4.0.0 2024-06-12 10:42 UTC

README

Build Status Scrutinizer Code Quality Code Coverage

Monitoring是一个应用程序监控和事件服务,它允许您从代码中进行监控和健康检查。

安装

按照常规要求库

composer require "pluggit/monitoring"

监控数据类型

指标

指标是在特定时刻获取的统计值,因此它可以被绘制和汇总以进行研究。

支持的指标

  • 计数器:跟踪某些事件发生的次数,例如数据库请求或页面浏览量。
  • 仪表:测量特定事物在特定时间点的值,例如汽车油箱中的燃油量或连接到系统的用户数量。
  • 直方图:跟踪一组值的统计分布,例如多个数据库查询的持续时间或用户上传的文件大小。
  • 集合:用于计算组中唯一元素的数量。如果您想跟踪网站的唯一访问者数量,集合是一个很好的选择。
  • 计时器:计时器实际上是直方图的一个特例,但专门发送时间度量。

事件

事件对于在指标上提供上下文信息很有用,例如标记新版本、服务器迁移或库更新。

如何使用Monitoring库

已定义了两个新实体来模拟现实世界的使用到代码。

指标实体

指标实体包含指标必须拥有的所有信息。

  • 名称:指标名称。
  • 类型:指标类型。
  • :指标值。根据指标类型不同而不同
  • 标签:与指标关联的标签,它必须是一个键值数组。使用它们来隔离数据。
  • 采样率:大于0且小于或等于1的整数。使用它来采样指标,例如:要仅发送指标集的10%,则设置采样率为0.1。

事件实体

事件实体描述了在某一特定时刻发生的事件。

  • 标题:简短的事件标题。
  • 文本:如果需要,事件的详细描述。
  • 主机:事件发生的主机。
  • 时间戳:事件发生的确切时间。
  • 标签:与指标关联的标签,它必须是一个键值数组。
  • 类型:指示事件类型:info、success、warning或error之一。

创建实体

创建了两个工厂来简化实体的创建,它们都允许一步创建实体并提供默认数据和标签。

  • MetricFactory:允许创建具有默认标签和前缀的指标。
  • EventFactory:允许创建具有默认主机和标签的事件实体。

注意:两个工厂都允许在实例化后使用方法添加更多默认标签。

public function addDefaultTags(array $tags);

将指标/事件发送到后端存储

一旦您有了这些实体之一,就可以将它们发送到不同的后端(例如日志文件、电子邮件、DataDog、statsd服务器等)。发送者知道如何将指标或事件发送到后端存储的类。

它们必须遵守Metric/SenderInterface接口以发送指标

public function send(AbstractMetric $metric);

Event/SenderInterface接口以发送事件

public function send(Event $event);

监控器

为了简化指标和事件的创建与发送,创建了一个新的类Monitor,对于大多数常见用例,您只需要与这个类进行交互。

监控器配置

监控器需要指标和事件工厂作为依赖项,还需要一个Monolog日志记录器来注册发现的可能异常。监控器将阻止所有异常抛出,因此使用监控器的代码的正常执行流程不会被监控库中的任何异常打断。创建监控器后,必须使用以下方法用指标和事件发送者填充它

public function pushMetricSender(MetricSender $sender);
public function pushEventSender(EventSender $sender);

注意:如果未将发送者推送到监控器,它将正常工作但不会将指标发送到任何后端,因此这是一种临时禁用监控器的好方法。

访问工厂

您可以使用这些访问器访问监控器内部的工厂(例如,添加更多默认标签)

public function getMetricFactory();
public function getEventFactory();

一步法

监控器可以通过一步方法创建指标和事件并将它们发送到所有后端

  • 计数器:此方法将创建并使用给定的计数发送计数器指标。
public function counter($metric, $count = 1, array $tags = [], $sampleRate = AbstractMetric::DEFAULT_SAMPLE_RATE)

$monitor->counter('wh.queries_executed', 38);
  • 增加:此方法将计数器指标增加+1并发送。
public function increment($metric, array $tags = [], $sampleRate = AbstractMetric::DEFAULT_SAMPLE_RATE)

$monitor->increment('wh.page_views', ['page' => 'site/home']);
  • 减少:此方法将计数器指标减少-1并发送。
public function decrement($metric, array $tags = [], $sampleRate = AbstractMetric::DEFAULT_SAMPLE_RATE)

$monitor->decrement('wh.remaining_slots');
  • 仪表:此方法将创建并使用给定的级别发送仪表指标。
public function gauge($metric, $level, array $tags = [], $sampleRate = AbstractMetric::DEFAULT_SAMPLE_RATE)

$monitor->gauge('wh.redis.memory_used', 736827);
  • 设置:它将创建一个具有给定唯一值的计数器并发送。
public function set($metric, $uniqueValue, array $tags = [], $sampleRate = AbstractMetric::DEFAULT_SAMPLE_RATE)

$monitor->set('wh.user', 314646); 
  • 直方图:此方法将创建并使用给定的毫秒数发送直方图指标。
public function histogram($metric, $duration, array $tags = [], $sampleRate = AbstractMetric::DEFAULT_SAMPLE_RATE)

$monitor->histogram('wh.user_creation', 325, ['controller' => 'api.user']); 
  • 开始:此方法将创建计时器并开始计算毫秒数,此方法不会立即发送指标。
public function start($metric, array $tags = [], $sampleRate = AbstractMetric::DEFAULT_SAMPLE_RATE)

$monitor->start('wh.user_creation', ['controller' => 'site.registration']);
  • 结束:必须在启动计时器后调用此方法,它将计算从开始时间到结束时间的耗时,然后发送指标。您还可以传递新的标签,这些标签将与启动计时器时指定的标签合并。
public function end($metric, array $tags = [])

$monitor->end('wh.user_creation', ['result' => 'ok']);
  • 事件:此方法将创建并使用当前时间(如果没有提供时间戳)发送事件。
public function event($title, $text, $type = Event::INFO, array $tags = [], $timestamp = null)

$monitor->event('release.1.55.1', 'features: WQR-615, WQR-634, WQR-645', Event::Success, ['deployer' => 'Sam'], strtotime('-10 minutes'));

使用监控器发送自定义指标或事件

监控器类还可以使用方法发送自定义指标和事件

public function sendMetric(AbstractMetric $metric);
public function sendEvent(Event $event);

典型设置

注意现在有一个可以用来简化创建方法的工厂,请参阅下一节 使用监控器的典型步骤是

  • 使用提供的指标和事件工厂创建监控器
  • 创建并将指标发送者和事件发送者推送到监控器
  • 开始使用监控器发送指标和事件

此代码是设置过程的简化演示,不包含对象依赖项。

// Build the metric factory with your choosen default tags
$metricFactory = new MetricFactory(['environment' => 'dev', 'mode' => 'production'], 'myapp-prefix.');

// Build the event factory with the host name and your choosen default tags
$eventFactory = new EventFactory('my_docker_hostname', ['environment' => 'dev', 'mode' => 'production', 'domain' => 'my_domain']);

// Build a Monolog Logger and push handlers
$logger = new Monolog\Logger('monitoring');
$logger->pushHandler(/* build handler for logging messages */);

// Build the monitor
$monitor = new Monitor($metricFactory, $eventFactory, $logger);

// Populate the monitor with the desired metric and event senders
$monitor
 ->pushMetricSender(new MonologMetricSender(/* object dependencies */))
 ->pushMetricSender(new DataDogMetricSender(/* object dependencies */))
 ->pushEventSender(new MonologMetricSender(/* object dependencies */))
 ->pushEventSender(new MonologMetricSender(/* object dependencies */));

// Use the monitor to send metrics and events
$monitor->increment('wh.page_views');

通过工厂创建

$monitor = MonitorFactory::create([
    'hostname'     => 'fooserver',        # Hostname of the server
    'default_tags' => ['foo' => 'bar'],   # A key-value array with default tags for metrics and events
    'prefix'       => 'my-app.',          # A prefix for the metrics
    'logger'       => [
        'instance' => $logger,            # A Psr\LoggerInterface instance
        'debug'    => true,               # If true, it will log debug messages from the monitor
        'level'    => LogLevel::DEBUG,    # The level for debug message
        'metrics'  => true,               # If true, metrics will be sent trough the provided logger instance
        'events'   => true,               # If true, events will be sent trough the provided logger instance
    ],
    'datadog'      => [
        'metrics'  => true,               # If true, metrics will be sent trough the datadog agent
        'events'   => true,               # If true, events will be sent trough the datadog agent
        'host'     => '10.0.0.1',         # The datadog agent host, if null the default will be used
        'port'     => 8822,               # The datadog agent port, if null the default will be used
    ],
]);

注意:工厂包含一些默认值,您可以在MonitorFactory代码中查看它们

可用的后端发送者

Psr-3 日志记录器

使用PSR-3兼容的发送者,您可以将事件和指标发送到PS-3 Logger Handlers。典型场景是将日志记录到文件,但您可以通过插件设置非常强大的处理程序,例如Monolog(允许您将日志记录到数据库、发送邮件或将指标和事件发送到在线平台如Splunk。当然,您也可以构建自定义的。)



Example of setup
```php
// Build the logger 
$logger = new \Monolog\Logger('monitoring');
$logger->pushHandler(new \Monolog\Handler\StreamHandler('/tmp/monitoring.log'));
// Push as many monolog handlers as you want

// Build the serializer
$serializer = \JMS\Serializer\SerializerBuilder::create()->build();

// Create the metric and/or event sender
$eventSender = new \Cmp\Infrastructure\Application\Monitoring\Monolog\Event\Sender($logger, $serializer);
$metricSender = new \Cmp\Infrastructure\Application\Monitoring\Monolog\Metric\Sender($logger, $serializer);

// Push them to the monitor
$monitor->pushMetricSender($metricSender);
$monitor->pushEventSender($eventSender);

发送者接受第二个参数level,这是日志记录器将用于创建消息的级别,因此您可以根据级别有不同发送者使用不同的日志记录器

$logger = new \Monolog\Logger('monitoring');
$logger->pushHandler(new \Monolog\AbstractHandler\StreamHandler('/tmp/monitoring.log'));
$logger->pushHandler(new \Monolog\AbstractHandler\StreamHandler('/tmp/monitoring_errors.log'), Logger::ERROR);

// This event sender will use error as level for generating the logger message, so only the second monolog handler will treat the events
$eventSender = new \Cmp\Infrastructure\Application\Monitoring\Monolog\Event\Sender($logger, serializer, Logger::ERROR);

// This event sender will log all events because both monolog handlers accept debug level and above
$eventSender = new \Cmp\Infrastructure\Application\Monitoring\Monolog\Event\Sender($logger, serializer, Logger::DEBUG);

DataDog

使用DataDog发送者,您将能够使用datadog代理上集成的stastd服务器将指标发送到DataDog,并使用HTTP API发送事件。

您想了解更多关于DataDog的信息吗?

查看配置快速指南这里

指标发送器

目前有2种指标发送器的实现

  • 发送器:默认实现,会为接收到的每个指标向datadog statsd服务器发送UDP消息
  • BufferedSender:此发送器将缓冲指标,直到达到指定的容量,然后在一个UDP消息中刷新多个指标。

关于BufferedSender的注意:在配置UDP消息的最大字节数时请小心,它依赖于机器和网络协议,最安全的值是默认值。如果消息太大,包将无法发送,指标将丢失

配置默认发送器的示例

// Datadog configuration
$datadogAgent = ['ip' => '127.0.0.1', 'port' => 8125];

// Build the sender
$socket = \Cmp\Infrastructure\Application\Monitoring\DataDog\Metric\Socket();
$metricSender = new \Cmp\Infrastructure\Application\Monitoring\DataDog\Metric\Sender($socket, datadogAgent['ip'], datadogAgent['port']);

// Push to the monitor
$monitor->pushMetricSender($metricSender);

事件发送器

您需要从datadog网页面板获取API密钥并生成一个应用程序密钥。

在配置发送器时,您需要创建API Events的新实例,该实例包含在库中,它需要一个传输来执行HTTP请求。目前库中有两个可用的实现,但您也可以构建自己的实现

  • CURL:这是API传输的本地CURL实现
  • Guzzle:它需要安装guzzle库,如composer.json文件中推荐的那样

使用原生CURL传输配置指标发送器的示例

// Build the API
$apiKey = 'YOUR API KEY';
$appKey = 'YOUR APPLICATION KEY';
$apiTransport = \Cmp\Infrastructure\Application\Monitoring\DataDog\Api\Transport\Curl(); 
$api = \Cmp\Infrastructure\Application\Monitoring\DataDog\Api\Api($apiTransport, $apiKey, $appKey);

// Create the events api SDK
$eventsApi = new \Cmp\Infrastructure\Application\Monitoring\DataDog\Api\Method\Events($api); 

// Build the sender
$eventSender = new \Cmp\Infrastructure\Application\Monitoring\DataDog\Event\Sender($eventsApi);

// Push it to the monitor
$monitor->pushEventSender($eventSender);

重要提示:此发送器将执行同步HTTP请求,因此不建议在用户应用程序中使用它。(查看消息后端发送器了解如何使用异步方式)

消息

这些发送器不是普通的发送器,因为它们不会直接对指标或事件执行操作。

这些后端发送器利用CMP/base库中包含的消息系统库,以便能够将指标和事件发送到消息系统,这样它们可以由其他发送器以异步方式处理

想象一下,如果我们想每次用户升级账户时都使用datadog事件发送器向DataDog发送一个事件,如果我们直接使用原生的datadog发送器,我们将通过同步调用DataDog的HTTP API阻塞用户,因此我们可以使用这个后端发送器来异步发送请求。

使用RabbitMQ作为消息系统的Message事件发送器的示例

//Setup the Rabbit producer
$rabbitProducer = \Cmp\Infrastructure\Application\Notification\RabbitMQ\Message\Producer($rabbitConfig);

// Build the sender with the producer and providing a destination exchange
$messageEventSender = new \Cmp\Infrastructure\Application\Monitoring\Message\Event\Sender($rabbitProducer, 'monitoring.events');

// Push it to the monitor
$monitor->pushEventSender($eventSender);

现在应该有一个其他守护进程任务,它将读取事件消息并将它们发送到其他发送器

// Build the rabbit consumer
$rabbitConsumer = new Cmp\Infrastructure\Application\Notification\RabbitMQ\Message\Consumer($rabbitConfig);

// The consumer requires a monolog logger to log errors
$logger = new \Monolog\Logger('monitoring');
$logger->pushHandler(new \Monolog\AbstractHandler\StreamHandler('/tmp/events_errors.log'));

// Build the consumer with the correct origin to read the messages
$messageEventConsumer = new \Cmp\Infrastructure\Application\Monitoring\Message\Event\Consumer($rabbitConsumer, $logger, 'monitoring.events';

// Push as many event senders as you want
$messageEventConsumer->pushSender($datadogEventSender);
$messageEventConsumer->pushSender($monologEventSender);

// Start listening to messages in an infinite loop
$messageEventConsumer->start();

关于异步指标的重要提示:指标没有时间戳,因此如果在消费消息时出现延迟,指标将会延迟。最坏的情况可能是如果消费者崩溃,然后稍后重新启动,它开始消费队列中的消息并生成大量带有错误时间戳的指标