Skip to content

Commit

Permalink
Add syslog logger implementation
Browse files Browse the repository at this point in the history
This implements RFC5424 version of the protocol.

See tbnobody#1819
  • Loading branch information
ranma committed Sep 21, 2024
1 parent 3265fc3 commit 44c89a5
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 0 deletions.
35 changes: 35 additions & 0 deletions include/SyslogLogger.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <WiFiUdp.h>
#include <TaskSchedulerDeclarations.h>
#include <mutex>

class SyslogLogger {
public:
SyslogLogger();
void init(Scheduler& scheduler);
void updateSettings(const String&& hostname);
void write(const uint8_t *buffer, size_t size);

private:
void loop();
void disable();
void enable();
bool resolveAndStart();
bool isResolved() const {
return _address != INADDR_NONE;
}

Task _loopTask;
std::mutex _mutex;
WiFiUDP _udp;
IPAddress _address;
String _syslog_hostname;
String _my_hostname;
String _proc_id;
String _header;
int _port;
bool _enabled;
};

extern SyslogLogger Syslog;
1 change: 1 addition & 0 deletions include/defaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

#define SYSLOG_ENABLED false
#define SYSLOG_PORT 514
#define SYSLOG_APPNAME "OpenDTU"

#define NTP_SERVER_OLD "pool.ntp.org"
#define NTP_SERVER "opendtu.pool.ntp.org"
Expand Down
5 changes: 5 additions & 0 deletions src/MessageOutput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* Copyright (C) 2022-2024 Thomas Basler and others
*/
#include "MessageOutput.h"
#include "SyslogLogger.h"

#include <Arduino.h>

Expand All @@ -26,6 +27,8 @@ void MessageOutputClass::register_ws_output(AsyncWebSocket* output)

size_t MessageOutputClass::write(uint8_t c)
{
Syslog.write(&c, 1);

if (_buff_pos < BUFFER_SIZE) {
std::lock_guard<std::mutex> lock(_msgLock);
_buffer[_buff_pos] = c;
Expand All @@ -39,6 +42,8 @@ size_t MessageOutputClass::write(uint8_t c)

size_t MessageOutputClass::write(const uint8_t* buffer, size_t size)
{
Syslog.write(buffer, size);

std::lock_guard<std::mutex> lock(_msgLock);
if (_buff_pos + size < BUFFER_SIZE) {
memcpy(&_buffer[_buff_pos], buffer, size);
Expand Down
5 changes: 5 additions & 0 deletions src/NetworkSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "NetworkSettings.h"
#include "Configuration.h"
#include "MessageOutput.h"
#include "SyslogLogger.h"
#include "PinMapping.h"
#include "Utils.h"
#include "defaults.h"
Expand Down Expand Up @@ -35,6 +36,8 @@ void NetworkSettingsClass::init(Scheduler& scheduler)

scheduler.addTask(_loopTask);
_loopTask.enable();

Syslog.init(scheduler);
}

void NetworkSettingsClass::NetworkEvent(const WiFiEvent_t event, WiFiEventInfo_t info)
Expand Down Expand Up @@ -281,6 +284,8 @@ void NetworkSettingsClass::applyConfig()
}
MessageOutput.println("done");
setStaticIp();

Syslog.updateSettings(getHostname());
}

void NetworkSettingsClass::setHostname()
Expand Down
138 changes: 138 additions & 0 deletions src/SyslogLogger.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2022-2024 Thomas Basler and others
*/
#include <HardwareSerial.h>
#include <ESPmDNS.h>
#include "defaults.h"
#include "SyslogLogger.h"
#include "Configuration.h"
#include "MessageOutput.h"
#include "NetworkSettings.h"

SyslogLogger::SyslogLogger()
: _loopTask(TASK_IMMEDIATE, TASK_FOREVER, std::bind(&SyslogLogger::loop, this))
{
}

void SyslogLogger::init(Scheduler& scheduler)
{
// PROCID change indicates a restart.
_proc_id = String(esp_random(), HEX);

scheduler.addTask(_loopTask);
_loopTask.enable();
}

void SyslogLogger::updateSettings(const String&& hostname)
{
auto config = Configuration.get().Syslog;

// Disable logger while it is reconfigured.
disable();

if (!config.Enabled) {
MessageOutput.println("[SyslogLogger] Syslog not enabled");
return;
}

_port = config.Port;
_my_hostname = hostname;
_syslog_hostname = config.Hostname;
if (_syslog_hostname.isEmpty()) {
MessageOutput.println("[SyslogLogger] Hostname not configured");
return;
}

MessageOutput.printf("[SyslogLogger] Logging to %s!\r\n", _syslog_hostname.c_str());

_header = "<7>1 - "; // RFC5424: Facility KERNEL, severity DEBUG, version 1, NIL timestamp.
_header += _my_hostname;
_header += " " SYSLOG_APPNAME " ";
_header += _proc_id;
// NIL values for message id and structured // data; utf-8 BOM.
_header += " - - \xEF\xBB\xBF";

// Enable logger.
enable();
}

void SyslogLogger::write(const uint8_t *buffer, size_t size)
{
std::lock_guard<std::mutex> lock(_mutex);
if (!_enabled || !isResolved()) {
return;
}
for (int i = 0; i < size; i++) {
uint8_t c = buffer[i];
bool overflow = false;
if (c >= 0x20) {
overflow = !_udp.write(c);
}
if (c == '\n' || overflow) {
_udp.endPacket();
_udp.beginPacket(_address, _port);
_udp.print(_header);
}
}
}

void SyslogLogger::disable()
{
MessageOutput.println("[SyslogLogger] Disable");
std::lock_guard<std::mutex> lock(_mutex);
if (_enabled) {
_enabled = false;
_address = INADDR_NONE;
_udp.stop();
}
}

void SyslogLogger::enable()
{
// Bind random source port.
if (!_udp.begin(0)) {
MessageOutput.println("[SyslogLogger] No sockets available");
return;
}

std::lock_guard<std::mutex> lock(_mutex);
_enabled = true;
}

bool SyslogLogger::resolveAndStart()
{
if (Configuration.get().Mdns.Enabled) {
_address = MDNS.queryHost(_syslog_hostname); // INADDR_NONE if failed
}
if (_address != INADDR_NONE) {
if (!_udp.beginPacket(_address, _port)) {
return false;
}
} else {
if (!_udp.beginPacket(_syslog_hostname.c_str(), _port)) {
return false;
}
_address = _udp.remoteIP(); // Store resolved address.
}
_udp.print(_header);
_udp.print("[SyslogLogger] Logging to ");
_udp.print(_syslog_hostname);
_udp.endPacket();
_udp.beginPacket(_address, _port);
_udp.print(_header);
return true;
}

void SyslogLogger::loop()
{
std::lock_guard<std::mutex> lock(_mutex);
if (!_enabled || !NetworkSettings.isConnected() || isResolved()) {
return;
}
if (!resolveAndStart()) {
_enabled = false;
}
}

SyslogLogger Syslog;

0 comments on commit 44c89a5

Please sign in to comment.