mirror of
https://github.com/esphome/esphome.git
synced 2026-02-08 08:41:59 +00:00
Merge remote-tracking branch 'origin/syslog_no_heap' into integration
This commit is contained in:
@@ -41,31 +41,39 @@ void Syslog::log_(const int level, const char *tag, const char *message, size_t
|
||||
len -= 11;
|
||||
}
|
||||
|
||||
// Build syslog packet on stack - 508 is max UDP packet size
|
||||
// Build syslog packet on stack (508 bytes chosen as practical limit for syslog over UDP)
|
||||
char packet[508];
|
||||
size_t offset = 0;
|
||||
size_t remaining = sizeof(packet);
|
||||
|
||||
// Write PRI
|
||||
int ret = snprintf(packet, sizeof(packet), "<%d>", pri);
|
||||
if (ret > 0)
|
||||
offset = ret;
|
||||
// Write PRI - abort if this fails as packet would be malformed
|
||||
int ret = snprintf(packet, remaining, "<%d>", pri);
|
||||
if (ret <= 0 || static_cast<size_t>(ret) >= remaining) {
|
||||
return;
|
||||
}
|
||||
offset = ret;
|
||||
remaining -= ret;
|
||||
|
||||
// Write timestamp directly into packet (RFC 5424: use "-" if time not valid)
|
||||
// Write timestamp directly into packet (RFC 5424: use "-" if time not valid or strftime fails)
|
||||
auto now = this->time_->now();
|
||||
if (now.is_valid()) {
|
||||
offset += now.strftime(packet + offset, sizeof(packet) - offset, "%b %e %H:%M:%S");
|
||||
} else {
|
||||
size_t ts_written = now.is_valid() ? now.strftime(packet + offset, remaining, "%b %e %H:%M:%S") : 0;
|
||||
if (ts_written > 0) {
|
||||
offset += ts_written;
|
||||
remaining -= ts_written;
|
||||
} else if (remaining > 0) {
|
||||
packet[offset++] = '-';
|
||||
remaining--;
|
||||
}
|
||||
|
||||
// Write hostname, tag, and message
|
||||
ret = snprintf(packet + offset, sizeof(packet) - offset, " %s %s: %.*s", App.get_name().c_str(), tag, (int) len,
|
||||
message);
|
||||
if (ret > 0)
|
||||
offset += ret;
|
||||
ret = snprintf(packet + offset, remaining, " %s %s: %.*s", App.get_name().c_str(), tag, (int) len, message);
|
||||
if (ret > 0) {
|
||||
// snprintf returns chars that would be written; clamp to actual buffer space
|
||||
offset += std::min(static_cast<size_t>(ret), remaining > 0 ? remaining - 1 : 0);
|
||||
}
|
||||
|
||||
if (offset > 0) {
|
||||
this->parent_->send_packet(reinterpret_cast<const uint8_t *>(packet), std::min(offset, sizeof(packet) - 1));
|
||||
this->parent_->send_packet(reinterpret_cast<const uint8_t *>(packet), offset);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,11 @@ api:
|
||||
"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"
|
||||
"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE"
|
||||
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
|
||||
- service: log_short_message
|
||||
then:
|
||||
- lambda: |-
|
||||
// Log a short message that should arrive complete (not truncated)
|
||||
ESP_LOGI("shorttest", "BEGIN|SHORT_MESSAGE_CONTENT|FINISH");
|
||||
|
||||
logger:
|
||||
level: DEBUG
|
||||
|
||||
@@ -33,7 +33,7 @@ class ParsedSyslogMessage(TypedDict):
|
||||
# Example: <134>Dec 20 14:30:45 syslog-test app: [D][app:029]: Running...
|
||||
SYSLOG_PATTERN = re.compile(
|
||||
r"<(\d+)>" # PRI (priority = facility * 8 + severity)
|
||||
r"(\S+ +\d+ \d+:\d+:\d+|-)" # TIMESTAMP (BSD format or NILVALUE "-")
|
||||
r"(\S+ +\d+ \d+:\d+:\d+|-)" # TIMESTAMP (BSD-style "%b %e %H:%M:%S", e.g. "Dec 20 14:30:45", or NILVALUE "-")
|
||||
r" (\S+)" # HOSTNAME
|
||||
r" (\S+):" # TAG
|
||||
r" (.*)" # MESSAGE
|
||||
@@ -258,3 +258,27 @@ async def test_syslog(
|
||||
assert "|END" not in trunc_msg, (
|
||||
"Message should be truncated before END marker"
|
||||
)
|
||||
|
||||
# Test short message - should arrive complete (not truncated)
|
||||
short_service = next(
|
||||
(s for s in services if s.name == "log_short_message"), None
|
||||
)
|
||||
assert short_service is not None, "log_short_message service not found"
|
||||
|
||||
await client.execute_service(short_service, {})
|
||||
|
||||
try:
|
||||
short_msg = await receiver.wait_for_pattern(r"shorttest.*BEGIN\|")
|
||||
except TimeoutError:
|
||||
pytest.fail(
|
||||
f"Short test message not received. Got: {receiver.messages[-10:]}"
|
||||
)
|
||||
|
||||
# Verify short message arrived complete with both markers
|
||||
assert "BEGIN|" in short_msg, "Short message missing BEGIN marker"
|
||||
assert "|FINISH" in short_msg, (
|
||||
f"Short message truncated unexpectedly: {short_msg}"
|
||||
)
|
||||
assert "SHORT_MESSAGE_CONTENT" in short_msg, (
|
||||
f"Short message content missing: {short_msg}"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user