Skip to content
This repository was archived by the owner on Oct 8, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
77 changes: 61 additions & 16 deletions components/syslog/syslog_component.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,21 @@

#include "esphome/core/log.h"
#include "esphome/core/application.h"
#include "esphome/core/version.h"

#ifdef USE_LOGGER
#include "esphome/components/logger/logger.h"
#endif
/*
#include "esphome/core/helpers.h"
#include "esphome/core/defines.h"
#include "esphome/core/version.h"
*/

#ifdef USE_SOCKET_IMPL_LWIP_TCP
#include <lwip/ip.h>
#define IPPROTO_UDP IP_PROTO_UDP
#endif

namespace esphome {
namespace syslog {

Expand All @@ -23,12 +28,53 @@ 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() {

/*
* Older versions of socket::set_sockaddr() return bogus results
* if trying to log to a Legacy IP address when IPv6 is enabled.
* Fixed by https://github.com/esphome/esphome/pull/7196
*/
this->server_socklen = 0;
if (ESPHOME_VERSION_CODE >= VERSION_CODE(2024, 8, 0)) {
this->server_socklen = socket::set_sockaddr((struct sockaddr *)&this->server, sizeof(this->server),
this->settings_.address, this->settings_.port);
}
#if USE_NETWORK_IPV6
else if (this->settings_.address.find(':') != std::string::npos) {
auto *server6 = reinterpret_cast<sockaddr_in6 *>(&this->server);
memset(server6, 0, sizeof(*server6));
server6->sin6_family = AF_INET6;
server6->sin6_port = htons(this->settings_.port);

ip6_addr_t ip6;
inet6_aton(this->settings_.address.c_str(), &ip6);
memcpy(server6->sin6_addr.un.u32_addr, ip6.addr, sizeof(ip6.addr));
this->server_socklen = sizeof(*server6);
}
#endif /* USE_NETWORK_IPV6 */
else {
auto *server4 = reinterpret_cast<sockaddr_in *>(&this->server);
memset(server4, 0, sizeof(*server4));
server4->sin_family = AF_INET;
server4->sin_addr.s_addr = inet_addr(this->settings_.address.c_str());
server4->sin_port = htons(this->settings_.port);
this->server_socklen = sizeof(*server4);
}
if (!this->server_socklen) {
ESP_LOGE(TAG, "Failed to parse server IP address '%s'", this->settings_.address.c_str());
this->mark_failed();
return;
}
this->socket_ = socket::socket(this->server.ss_family, SOCK_DGRAM, IPPROTO_UDP);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IPPROTO_UDP is not defined on arduino for esp8266.
I managed to fix this by adding

#ifndef IPPROTO_UDP
#include <lwip/ip.h>
#define IPPROTO_UDP IP_PROTO_UDP
#endif

Maybe there is a better way but this works for me. (Also tested with esp-idf.)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made it #ifdef USE_SOCKET_IMPL_LWIP_TCP; does that work for you?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And also, does that make it work or just make it build? The comment at esphome/esphome#4969 (comment) seems to suggest that it'll still just use TCP? Is it actually connecting to the syslog server over TCP?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so as it is right now esp8266 doesn't work, also verified that

#ifdef USE_SOCKET_IMPL_LWIP_TCP
#include <lwip/ip.h>
#define IPPROTO_UDP IP_PROTO_UDP
#endif

is in the source file

if (!this->socket_) {
ESP_LOGE(TAG, "Failed to create UDP socket");
this->mark_failed();
return;
}

this->log(ESPHOME_LOG_LEVEL_INFO , "syslog", "Syslog started");
ESP_LOGI(TAG, "Started");

Expand All @@ -51,23 +97,22 @@ void SyslogComponent::loop() {
}

void SyslogComponent::log(uint8_t level, const std::string &tag, const std::string &payload) {

if (this->is_failed())
return;

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())) {
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