Skip to content

Commit

Permalink
Fix esp-idf and IPv6 support by using plain UDP socket, drop Syslog l…
Browse files Browse the repository at this point in the history
…ibrary

It turns out to be fairly simple to just send the UDP packets directly,
and the UDP socket handling can then be a whole lot more generic.
  • Loading branch information
David Woodhouse authored and dwmw2 committed Aug 5, 2024
1 parent 6cab198 commit e6d3aad
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 45 deletions.
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

A simple syslog component for esphome. The component is designed to auto attach itself to the logger core module (like the MQTT component does with the `log_topic`)

This component uses the https://github.com/arcao/Syslog library version 2.0 at its core

## How to

### Manually
Expand Down
23 changes: 9 additions & 14 deletions components/syslog/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,22 @@
CONF_ENABLE_LOGGER_MESSAGES = "enable_logger"
CONF_MIN_LEVEL = "min_level"

DEPENDENCIES = ['logger','network']
DEPENDENCIES = ['logger','network','socket']

debug_ns = cg.esphome_ns.namespace('debug')
syslog_ns = cg.esphome_ns.namespace('syslog')

SyslogComponent = syslog_ns.class_('SyslogComponent', cg.Component)
SyslogLogAction = syslog_ns.class_('SyslogLogAction', automation.Action)

CONFIG_SCHEMA = cv.All(
cv.Schema({
cv.GenerateID(): cv.declare_id(SyslogComponent),
cv.Optional(CONF_IP_ADDRESS, default="255.255.255.255"): cv.string_strict,
cv.Optional(CONF_PORT, default=514): cv.port,
cv.Optional(CONF_ENABLE_LOGGER_MESSAGES, default=True): cv.boolean,
cv.Optional(CONF_STRIP_COLORS, default=True): cv.boolean,
cv.Optional(CONF_MIN_LEVEL, default="DEBUG"): is_log_level,
}),
cv.only_with_arduino,
)
CONFIG_SCHEMA = cv.Schema({
cv.GenerateID(): cv.declare_id(SyslogComponent),
cv.Optional(CONF_IP_ADDRESS, default="255.255.255.255"): cv.string_strict,
cv.Optional(CONF_PORT, default=514): cv.port,
cv.Optional(CONF_ENABLE_LOGGER_MESSAGES, default=True): cv.boolean,
cv.Optional(CONF_STRIP_COLORS, default=True): cv.boolean,
cv.Optional(CONF_MIN_LEVEL, default="DEBUG"): is_log_level,
})

SYSLOG_LOG_ACTION_SCHEMA = cv.Schema({
cv.GenerateID(): cv.use_id(SyslogComponent),
Expand All @@ -36,8 +33,6 @@
})

def to_code(config):
cg.add_library('Syslog', '2.0.0')

var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)

Expand Down
41 changes: 23 additions & 18 deletions components/syslog/syslog_component.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,26 @@ static const uint8_t esphome_to_syslog_log_levels[] = {0, 3, 4, 6, 5, 7, 7, 7};

SyslogComponent::SyslogComponent() {
this->settings_.client_id = App.get_name();
// Get the WifiUDP client here instead of getting it in setup() to make sure we always have a client when calling log()
// Calling log() without the device connected should not be an issue since there is a wifi connected check and WifiUDP fails "silently" and doesn't generate an exception anyways
this->udp_ = new WiFiUDP();
}

void SyslogComponent::setup() {

this->server_socklen = socket::set_sockaddr((struct sockaddr *)&this->server, sizeof(this->server),
this->settings_.address, this->settings_.port);
if (!this->server_socklen) {
ESP_LOGW(TAG, "Failed to parse server IP address '%s'", this->settings_.address.c_str());
return;
}
this->socket_ = socket::socket(this->server.ss_family, SOCK_DGRAM, IPPROTO_UDP);
if (!this->socket_) {
ESP_LOGW(TAG, "Failed to create UDP socket");
return;
}

this->log(ESPHOME_LOG_LEVEL_INFO , "syslog", "Syslog started");
ESP_LOGI(TAG, "Started");
ESP_LOGI(TAG, "Started to %d %s", this->server.ss_family, this->settings_.address.c_str());

#ifdef USE_LOGGER
#ifdef USE_LOGGER
if (logger::global_logger != nullptr) {
logger::global_logger->add_on_log_callback([this](int level, const char *tag, const char *message) {
if(!this->enable_logger || (level > this->settings_.min_log_level)) return;
Expand All @@ -53,22 +63,17 @@ void SyslogComponent::loop() {
void SyslogComponent::log(uint8_t level, const std::string &tag, const std::string &payload) {
level = level > 7 ? 7 : level;

// Simple check to make sure that there is connectivity, if not, log the issue and return
if(WiFi.status() != WL_CONNECTED) {
ESP_LOGW(TAG, "Tried to send \"%s\"@\"%s\" with level %d but Wifi isn't connected yet", tag.c_str(), payload.c_str(), level);
if (!this->socket_) {
ESP_LOGW(TAG, "Tried to send \"%s\"@\"%s\" with level %d but socket isn't connected", tag.c_str(), payload.c_str(), level);
return;
}

Syslog syslog(
*this->udp_,
this->settings_.address.c_str(),
this->settings_.port,
this->settings_.client_id.c_str(),
tag.c_str(),
LOG_KERN
);
if(!syslog.log(esphome_to_syslog_log_levels[level], payload.c_str())) {
ESP_LOGW(TAG, "Tried to send \"%s\"@\"%s\" with level %d but but failed for an unknown reason", tag.c_str(), payload.c_str(), level);
int pri = esphome_to_syslog_log_levels[level];
std::string buf = str_sprintf("<%d>1 - %s %s - - - \xEF\xBB\xBF%s",
pri, this->settings_.client_id.c_str(),
tag.c_str(), payload.c_str());
if (this->socket_->sendto(buf.c_str(), buf.length(), 0, (struct sockaddr *)&this->server, this->server_socklen) < 0) {
ESP_LOGW(TAG, "Tried to send \"%s\"@\"%s\" with level %d but but failed for an unknown reason", tag.c_str(), payload.c_str(), level);
}
}

Expand Down
15 changes: 4 additions & 11 deletions components/syslog/syslog_component.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,7 @@
#include "esphome/core/defines.h"
#include "esphome/core/automation.h"
#include "esphome/core/log.h"
#include <Syslog.h>
#include <Udp.h>

#if defined ESP8266 || defined ARDUINO_ESP8266_ESP01
#include <ESP8266WiFi.h>
#else
#include <WiFi.h>
#endif

#include <WiFiUdp.h>
#include "esphome/components/socket/socket.h"

namespace esphome {
namespace syslog {
Expand Down Expand Up @@ -51,7 +42,9 @@ class SyslogComponent : public Component {
bool strip_colors;
bool enable_logger;
SYSLOGSettings settings_;
UDP *udp_ = NULL;
std::unique_ptr<socket::Socket> socket_ = nullptr;
struct sockaddr_storage server;
socklen_t server_socklen;
};

template<typename... Ts> class SyslogLogAction : public Action<Ts...> {
Expand Down

0 comments on commit e6d3aad

Please sign in to comment.