Skip to content

Commit

Permalink
ITKDev: Fixed sending data into loki
Browse files Browse the repository at this point in the history
  • Loading branch information
cableman committed Apr 23, 2024
1 parent 9809589 commit 1345bc2
Show file tree
Hide file tree
Showing 10 changed files with 101 additions and 59 deletions.
2 changes: 1 addition & 1 deletion modules/os2forms_audit/os2forms_audit.services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ services:
arguments: ['@plugin.manager.os2forms_audit_logger', '@config.factory']

os2forms_audit.commands:
class: Drupal\os2forms_audit\Commands\Os2FormsAuditDrushCommands
class: Drupal\os2forms_audit\Commands\AuditLogDrushCommands
arguments: ['@os2forms_audit.logger']
tags:
- { name: drush.command }
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public function __construct(
* @throws \Drupal\Component\Plugin\Exception\PluginException
*/
public function logMessage(string $log_message = ''): void {
$this->auditLogger->log(time(), $log_message, []);
$this->auditLogger->log('test', time(), $log_message, ['from' => 'drush']);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ interface AuditLoggerInterface extends PluginInspectionInterface {
/**
* Logs a message with optional metadata.
*
* @param string $type
* The type of event to log (auth, lookup etc.)
* @param int $timestamp
* The timestamp of the log entry.
* @param string $line
Expand All @@ -20,6 +22,6 @@ interface AuditLoggerInterface extends PluginInspectionInterface {
* Additional metadata associated with the log entry. Defaults to an empty
* array.
*/
public function log(int $timestamp, string $line, array $metadata = []): void;
public function log(string $type, int $timestamp, string $line, array $metadata = []): void;

}
3 changes: 2 additions & 1 deletion modules/os2forms_audit/src/Plugin/AuditLogger/File.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,13 @@ public function __construct(array $configuration, $plugin_id, $plugin_definition
/**
* {@inheritdoc}
*/
public function log(int $timestamp, string $line, array $metadata = []): void {
public function log(string $type, int $timestamp, string $line, array $metadata = []): void {
// Code to write the entity to a file.
// This is just a placeholder and won't write the data.
file_put_contents(
$this->configuration['file'],
json_encode([
'type' => $type,
'epoc' => $timestamp,
'line' => $line,
'metadata' => $metadata,
Expand Down
27 changes: 13 additions & 14 deletions modules/os2forms_audit/src/Plugin/AuditLogger/Loki.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\PluginBase;
use Drupal\Core\Plugin\PluginFormInterface;
use Drupal\os2forms_audit\Service\LokiClient;

/**
* Stores entities in the database.
Expand All @@ -18,16 +19,26 @@
*/
class Loki extends PluginBase implements AuditLoggerInterface, PluginFormInterface, ConfigurableInterface {

/**
* {@inheritdoc}
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->setConfiguration($configuration);
}

/**
* {@inheritdoc}
*
* @throws \JsonException
*/
public function log(int $timestamp, string $line, array $metadata = []): void {
// @todo use loki client to send message to loki
public function log(string $type, int $timestamp, string $line, array $metadata = []): void {
$client = new LokiClient([
'entrypoint' => $this->configuration['entrypoint'],
'auth' => $this->configuration['auth'],
]);
// Convert timestamp to nanoseconds.
$client->send($type, $timestamp * 1000000000, $line, $metadata);
}

/**
Expand Down Expand Up @@ -70,13 +81,11 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta
'username' => [
'#type' => 'textfield',
'#title' => $this->t('Username'),
'#required' => TRUE,
'#default_value' => $this->configuration['auth']['username'],
],
'password' => [
'#type' => 'password',
'#title' => $this->t('Password'),
'#required' => TRUE,
'#default_value' => $this->configuration['auth']['password'],
],
];
Expand All @@ -101,16 +110,6 @@ public function validateConfigurationForm(array &$form, FormStateInterface $form
$form_state->setErrorByName('entrypoint', $this->t('Invalid URL.'));
}

// Validate auth username.
if (empty($values['auth']['username'])) {
$form_state->setErrorByName('auth][username', $this->t('Username is required.'));
}

// Validate auth password.
if (empty($values['auth']['password'])) {
$form_state->setErrorByName('auth][password', $this->t('Password is required.'));
}

$curlOptions = array_filter(explode(',', $values['curl_options']));
foreach ($curlOptions as $option) {
[$key] = explode(' =>', $option);
Expand Down
8 changes: 6 additions & 2 deletions modules/os2forms_audit/src/Plugin/AuditLogger/Watchdog.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,17 @@ class Watchdog extends PluginBase implements AuditLoggerInterface {
/**
* {@inheritdoc}
*/
public function log(int $timestamp, string $line, array $metadata = []): void {
public function log(string $type, int $timestamp, string $line, array $metadata = []): void {
$data = '';
array_walk($metadata, function ($val, $key) use (&$data) {
$data .= " $key=\"$val\"";
});

\Drupal::logger('os2forms_audit')->info($line . ' (%data)', ['data' => $data]);
\Drupal::logger('os2forms_audit')->info('%type: %line (%data)', [
'type' => $type,
'line' => $line,
'data' => $data,
]);
}

}
2 changes: 1 addition & 1 deletion modules/os2forms_audit/src/Plugin/Derivative/LocalTask.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
class LocalTask extends DeriverBase implements ContainerDeriverInterface {

public function __construct(
private readonly LoggerManager $loggerManager
private readonly LoggerManager $loggerManager,
) {
}

Expand Down
6 changes: 4 additions & 2 deletions modules/os2forms_audit/src/Service/Logger.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ public function __construct(
/**
* Logs a message using a plugin-specific logger.
*
* @param string $type
* The type of event to log (auth, lookup etc.)
* @param int $timestamp
* The timestamp for the log message.
* @param string $line
Expand All @@ -32,14 +34,14 @@ public function __construct(
*
* @throws \Drupal\Component\Plugin\Exception\PluginException
*/
public function log(int $timestamp, string $line, array $metadata = []): void {
public function log(string $type, int $timestamp, string $line, array $metadata = []): void {
$config = $this->configFactory->get(SettingsForm::$configName);
$plugin_id = $config->get('provider');

$configuration = $this->configFactory->get(PluginSettingsForm::getConfigName())->get($plugin_id);
$logger = $this->loggerManager->createInstance($plugin_id, $configuration ?? []);

$logger->log($timestamp, $line, $metadata);
$logger->log($type, $timestamp, $line, $metadata);
}

}
66 changes: 30 additions & 36 deletions modules/os2forms_audit/src/Service/LokiClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*
* This is based/inspired by https://github.com/itspire/monolog-loki.
*/
class LokiClient {
class LokiClient implements LokiClientInterface {

/**
* Location of the loki entry point.
Expand Down Expand Up @@ -49,52 +49,34 @@ public function __construct(
$this->entrypoint = $this->getEntrypoint($apiConfig['entrypoint']);
$this->customCurlOptions = $apiConfig['curl_options'] ?? [];

if (isset($apiConfig['auth']['basic'])) {
$this->basicAuth = (2 === count($apiConfig['auth']['basic'])) ? $apiConfig['auth']['basic'] : [];
if (isset($apiConfig['auth']) && !empty($apiConfig['auth']['username']) && !empty($apiConfig['auth']['password'])) {
$this->basicAuth = $apiConfig['auth'];
}
}

/**
* Send a log message to Loki ingestion endpoint.
*
* Message format sendt to loki in the following json format.
* {
* "Streams": [
* {
* "stream": {
* "label": "value"
* },
* "values": [
* [ "<unix epoch in nanoseconds>", "<log line>", <structured metadata> ]
* ]
* }
* ]
* }
*
* @param string $label
* Loki global label to use.
* @param int $epoch
* Unix epoch in nanoseconds.
* @param string $line
* The log line to send.
* @param array $metadata
* Structured metadata.
*
* @see https://grafana.com/docs/loki/latest/reference/api/#ingest-logs
* {@inheritdoc}
*
* @throws \JsonException
*/
public function send(string $label, int $epoch, string $line, array $metadata = []): void {
$this->sendPacket([
'streams' => [
$packet = [
'streams' => [[
'stream' => [
'label' => $label,
'app' => 'os2forms',
'type' => $label,
],
'values' => [
[$epoch, $line, $metadata],
[(string) $epoch, $line],
],
],
]);
]],
];

if (!empty($metadata)) {
$packet['streams'][0]['stream'] += $metadata;
}

$this->sendPacket($packet);
}

/**
Expand Down Expand Up @@ -159,7 +141,19 @@ private function sendPacket(array $packet): void {
}

curl_setopt_array($this->connection, $curlOptions);
curl_exec($this->connection);
$result = curl_exec($this->connection);

if (FALSE === $result){
throw new \RuntimeException('Error sending packet to Loki');
}

if (curl_errno($this->connection)) {
// If an error occurred, output it
echo 'Curl error: ' . curl_error($this->connection);
} else {
// No error occurred, print out the result of the request
echo 'Curl result: ' . $result;
}
}
}

Expand Down
40 changes: 40 additions & 0 deletions modules/os2forms_audit/src/Service/LokiClientInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

namespace Drupal\os2forms_audit\Service;

/**
* Interface for sending log messages to Loki ingestion endpoint.
*/
interface LokiClientInterface {

/**
* Send a log message to Loki ingestion endpoint.
*
* Message format sent to loki in the following json format.
* {
* "Streams": [
* {
* "stream": {
* "label": "value"
* },
* "values": [
* [ "<unix epoch in nanoseconds>", "<log line>"]
* ]
* }
* ]
* }
*
* @param string $label
* Loki global label to use.
* @param int $epoch
* Unix epoch in nanoseconds.
* @param string $line
* The log line to send.
* @param array $metadata
* Extra labels/metadata to filter on.
*
* @see https://grafana.com/docs/loki/latest/reference/api/#ingest-logs
*/
public function send(string $label, int $epoch, string $line, array $metadata = []): void;

}

0 comments on commit 1345bc2

Please sign in to comment.