Skip to content

add syslog function to wled #4664

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open

add syslog function to wled #4664

wants to merge 9 commits into from

Conversation

KrX3D
Copy link

@KrX3D KrX3D commented Apr 26, 2025

WLED Syslog Component

Overview

Adds a SyslogPrinter to the WLED core that captures all debug-print output and forwards it—over UDP—to a remote syslog server, in any of three standard formats (BSD/RFC3164, RFC5424 or raw text). This makes it easy to integrate WLED logs into your existing centralized logging/monitoring infrastructure.

How it works

1. Print interception & buffering

  • Capturing all debug-print output.
  • Characters are accumulated in a 128-byte buffer.
  • On newline (or buffer full), flushBuffer() trims any trailing \r, null-terminates, and sends the complete message over UDP.

2. Hostname resolution

  • The first time you send (or after changing host), resolveHostname() does a DNS lookup via WiFi.hostByName() (or ETH.hostByName() on Ethernet builds) and caches the resulting IP.

3. Message formatting & UDP send

  • Priority (PRI) = (facility << 3) | severity.
  • Uses WiFiUDP to emit one packet per message.
  • Supports three protocols:
    1. BSD (RFC 3164)
      <PRI>TIMESTAMP HOST APP-NAME: MESSAGE
      
    2. RFC 5424
      <PRI>1 TIMESTAMP-ISO HOST APP-NAME – – – MESSAGE
      
    3. RAW
      MESSAGE
      

In RAW mode the message payload is same as WLED’s existing NetDebug output—without any PRI, timestamp or header added.

Example log output

Apr 26 13:54:59 EleksTube WLED: ===== WLED SYSLOG CONFIGURATION =====
Apr 26 13:54:59 EleksTube WLED:  Hostname:  192.168.1.13
Apr 26 13:54:59 EleksTube WLED:  Cached IP:  192.168.1.13
Apr 26 13:54:59 EleksTube WLED:  Port:       514
Apr 26 13:54:59 EleksTube WLED:  Protocol:   0 (BSD)
Apr 26 13:54:59 EleksTube WLED:  Facility:   20 (LCL4)
Apr 26 13:54:59 EleksTube WLED:  Severity:   7 (DEBUG)
Apr 26 13:54:59 EleksTube WLED: ======================================

Usage

Build-time configuration (platform.ini)

Enable debug output and syslog in your platform.ini:

; Core debug output (required for syslog forwarding)
-D WLED_DEBUG

; Enable the syslog printer
-D WLED_ENABLE_SYSLOG

; Optional overrides (shown with defaults)
; -D WLED_SYSLOG_HOST='""' ;'"192.168.1.13"'
; -D WLED_SYSLOG_PORT=514
; -D WLED_SYSLOG_PROTOCOL=SYSLOG_PROTO_BSD
; -D WLED_SYSLOG_FACILITY=SYSLOG_LOCAL4
; -D WLED_SYSLOG_SEVERITY=SYSLOG_DEBUG
  • WLED_DEBUG must be defined so debug-print calls are compiled in—and thus forwarded to syslog.
  • WLED_ENABLE_SYSLOG turns on the syslog component.
  • WLED_SYSLOG_HOST sets the target server.
  • The optional flags override port, protocol, facility and minimum severity.

Runtime configuration via GUI

In the WLED web interface, go to Settings → Sync (at the bottom) to enable/disable syslog and adjust:

  • Syslog Enabled (on/off)
  • Host (IPv4 or DNS name)
  • Port (UDP port, default 514)
  • Protocol: BSD (RFC3164) / RFC5424 / RAW
  • Facility: KERN, USER, MAIL, DAEMON, AUTH, SYSLOG, LPR, NEWS, UUCP, CRON, AUTHPRIV, FTP, NTP, LOG_AUDIT, LOG_ALERT, CLOCK_DAEMON, LOCAL0…LOCAL7
  • Severity: EMERG, ALERT, CRIT, ERR, WARNING, NOTICE, INFO, DEBUG

…

You can also toggle syslog on/off under Info & Debug on the main page.

…

Summary by CodeRabbit

  • New Features

    • Added syslog support for debug output with configurable protocol (BSD, RFC5424, Raw), facility, and severity levels.
    • Introduced a Syslog configuration section in the settings UI for host, port, protocol, facility, and severity setup.
    • Syslog settings are manageable via the web interface and included in configuration import/export.
    • Syslog client initialization, hostname resolution, and message sending integrated into system setup.
    • Added build scripts to inject and restore the Syslog UI section automatically during firmware builds.
  • Bug Fixes

    • Disabled debug output pin and USB CDC serial debug output when syslog is enabled to avoid conflicts.
  • Documentation

    • Enhanced settings UI and scripts to include syslog configuration options.

Copy link
Contributor

coderabbitai bot commented Apr 26, 2025

Warning

Rate limit exceeded

@KrX3D has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 1 minutes and 16 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 14910fc and 0f50d28.

📒 Files selected for processing (1)
  • pio-scripts/inject_syslog_ui.py (1 hunks)

Walkthrough

This change set introduces syslog support as a new debug output option in the WLED project. The syslog functionality is conditionally compiled using the WLED_ENABLE_SYSLOG macro and includes configuration, serialization, deserialization, and UI integration for syslog parameters such as host, port, protocol, facility, and severity. A new SyslogPrinter class is added to handle UDP-based syslog message transmission, supporting multiple syslog protocol formats. The settings UI and JSON configuration are extended to allow users to enable and configure syslog. Existing debug output logic is updated to support syslog as an alternative to serial or network debug output, with appropriate initialization and conditional handling throughout the codebase.

Changes

Files/Paths Change Summary
wled00/syslog.h, wled00/syslog.cpp Introduced a new SyslogPrinter class and supporting header for UDP-based syslog message sending. Defines syslog facilities, severities, and protocol formats. Adds a global Syslog instance for use as a debug output. Implements hostname resolution, buffering, and message formatting for BSD, RFC 5424, and raw protocols.
wled00/wled.h, wled00/bus_manager.h Expanded debug output configuration to support syslog via the WLED_ENABLE_SYSLOG macro. Added global syslog configuration variables and set DEBUGOUT to use Syslog when enabled. Maintained previous behaviors for network and serial debug output.
wled00/cfg.cpp, wled00/json.cpp Added syslog configuration fields to JSON serialization/deserialization routines under the WLED_ENABLE_SYSLOG flag. Ensured syslog enablement is reflected in configuration and info outputs.
wled00/set.cpp, wled00/wled.cpp Integrated syslog configuration and initialization into settings handling and setup routines. Added code to read syslog parameters from HTTP requests and initialize the syslog client accordingly. Excluded conflicting debug pin and serial configurations when syslog is enabled.
wled00/data/settings_sync.htm, wled00/xml.cpp Added placeholder comments for a syslog configuration section in the settings UI HTML. Extended JavaScript settings generation to include syslog parameters and toggle visibility based on enablement. Updated reserved pins logic to exclude debug TX pin when syslog is enabled.
pio-scripts/inject_syslog_ui.py Added a new build script to inject or restore the syslog configuration UI section in the settings HTML file during build. Manages backup and restoration of the original file based on syslog enablement and build type, ensuring the UI section is present only when syslog is enabled.
platformio.ini Added the new pio-scripts/inject_syslog_ui.py script to the extra_scripts list to run before the existing UI build script, enabling automated syslog UI injection during builds.

Suggested reviewers

  • blazoncek
  • softhack007
✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (3)
wled00/syslog.h (2)

58-58: Remove the unused test variable.

This boolean member variable doesn't appear to be used anywhere in the implementation and seems to be leftover debug code.

-    bool test = true;

60-60: Consider a configurable buffer size.

The fixed 128-byte buffer might be too small for complex log messages, especially when including timestamps and other syslog metadata. Consider making this configurable or handling message truncation more explicitly.

You could add a compile-time configuration option for the buffer size:

-    char _buffer[128]; // Buffer for collecting characters
+    #ifndef SYSLOG_BUFFER_SIZE
+    #define SYSLOG_BUFFER_SIZE 128
+    #endif
+    char _buffer[SYSLOG_BUFFER_SIZE]; // Buffer for collecting characters
wled00/syslog.cpp (1)

135-149: Add year to BSD syslog timestamp.

The BSD format timestamp doesn't include the year, which could cause issues with log aggregation over year boundaries. Consider adding the year or a configuration option to include it.

if (ntpEnabled && ntpConnected) {
  // Month abbreviation
  const char* months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", 
                         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
  
-  syslogUdp.printf("%s %2d %02d:%02d:%02d ", 
+  syslogUdp.printf("%s %2d %04d %02d:%02d:%02d ", 
                   months[month(localTime) - 1], 
                   day(localTime),
+                  year(localTime),
                   hour(localTime), 
                   minute(localTime), 
                   second(localTime));
} else {
  // No valid time available
-  syslogUdp.print("Jan 01 00:00:00 ");
+  syslogUdp.print("Jan 01 1970 00:00:00 ");
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 410025f and 25c4c5b.

📒 Files selected for processing (10)
  • wled00/bus_manager.h (1 hunks)
  • wled00/cfg.cpp (2 hunks)
  • wled00/data/settings_sync.htm (1 hunks)
  • wled00/json.cpp (2 hunks)
  • wled00/set.cpp (1 hunks)
  • wled00/syslog.cpp (1 hunks)
  • wled00/syslog.h (1 hunks)
  • wled00/wled.cpp (3 hunks)
  • wled00/wled.h (1 hunks)
  • wled00/xml.cpp (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
wled00/xml.cpp (2)
wled00/fcn_declare.h (4)
  • printSetFormCheckbox (498-498)
  • settingsScript (421-421)
  • printSetFormValue (499-499)
  • printSetFormValue (500-500)
wled00/util.cpp (6)
  • printSetFormCheckbox (98-100)
  • printSetFormCheckbox (98-98)
  • printSetFormValue (101-103)
  • printSetFormValue (101-101)
  • printSetFormValue (108-110)
  • printSetFormValue (108-108)
🔇 Additional comments (16)
wled00/bus_manager.h (1)

26-35: Well-implemented syslog integration in debug output mechanism

The conditional inclusion of syslog support is correctly ordered to prioritize syslog over network debug and serial output. This maintains backward compatibility while extending functionality.

wled00/data/settings_sync.htm (1)

240-292: Well-structured Syslog UI section

The Syslog settings section is well-organized and follows the existing UI patterns. All relevant syslog parameters (enable/disable, host, port, protocol, facility, severity) are included with appropriate options.

wled00/set.cpp (1)

476-496: Thorough parameter validation in syslog configuration handler

The implementation correctly validates all syslog parameters before applying them, including checking for valid ranges for protocol, facility, and severity. The immediate initialization of the syslog client ensures changes take effect right away.

wled00/wled.cpp (3)

332-334: Proper conditional for USB CDC debug output

Good modification to prevent disabling kernel messages when syslog is enabled, maintaining debug output capabilities when needed.


390-392: Avoid TX pin allocation when using syslog

Correctly prevents allocating the hardware TX pin for debug output when syslog is enabled, avoiding potential pin conflicts.


425-430: Clean syslog initialization during setup

The syslog client is properly initialized with the configured parameters and application name during setup. This ensures syslog is ready to use as soon as the system starts.

wled00/cfg.cpp (2)

539-547: Good implementation of syslog configuration deserialization.

The code adds proper support for reading syslog configuration from a JSON file, following the existing patterns used for other network services. All necessary syslog parameters are included and properly contained within the conditional compilation directive.


1064-1072: Well-structured syslog configuration serialization.

This implementation correctly writes syslog configuration to JSON, maintaining consistency with other configuration sections. Good use of conditional compilation to ensure the code is only included when syslog is enabled.

wled00/json.cpp (2)

302-305: Good addition of syslog toggle via JSON API with feedback.

The implementation correctly enables enabling/disabling syslog via the JSON API, with appropriate debug feedback. It follows the same pattern as the existing debug options, maintaining consistency.


787-789: Consistent implementation of syslog flags in serialized info.

This change properly updates the os flags to reflect syslog debug status in the serialized JSON output, following the same bit manipulation pattern used for other debug options. Excellent consistency with existing code.

wled00/xml.cpp (2)

108-108: Correct update to debug pin reservation logic.

This change ensures the TX pin isn't needlessly reserved when syslog debugging is enabled, allowing it to be used for other purposes. Good attention to detail in working with the existing conditional compilation logic.


520-529: Well-implemented syslog settings UI integration.

The code adds all necessary UI elements for syslog configuration using existing helper functions. The toggle for hiding syslog settings when not compiled in follows the same pattern used for other optional features. Clean implementation.

wled00/wled.h (2)

967-992: Well-structured syslog globals and configuration defaults.

This implementation properly adds all necessary global variables and default settings for syslog functionality. The code is well-documented with helpful comments and follows the established patterns for configuration macros.

Each setting has a sensible default that can be overridden at compile time, and the naming conventions are consistent with the rest of the codebase.


993-993: Correct modification to debug output selection chain.

Changed #ifdef to #elif to properly form a conditional chain with the new syslog section, ensuring only one debug output mechanism is selected.

wled00/syslog.cpp (2)

104-111: ⚠️ Potential issue

Prevent buffer overflow in write method.

The buffer check should use >= instead of < to ensure there's always room for the null terminator.

size_t SyslogPrinter::write(uint8_t c) {
  // Store in buffer regardless of connection status
- if (_bufferIndex < sizeof(_buffer) - 1) {
+ if (_bufferIndex < sizeof(_buffer) - 1) { // Leave space for null terminator
    _buffer[_bufferIndex++] = c;
  }
  
  // If newline or buffer full, flush
- if (c == '\n' || _bufferIndex >= sizeof(_buffer) - 1) {
+ if (c == '\n' || _bufferIndex >= sizeof(_buffer) - 1) {
    flushBuffer();
  }

Likely an incorrect or invalid review comment.


64-65:

❌ Incorrect review comment

Reduce dependency on global variables.

The code depends on global variables like WLED_CONNECTED and syslogEnabled which creates tight coupling and makes testing difficult. Consider passing these as parameters or having more self-contained logic.

bool SyslogPrinter::resolveHostname() {
-  if (!WLED_CONNECTED || !syslogEnabled) return false;
+  // Check connection status locally - can be a class method or passed as parameter
+  bool isConnected = WLED_CONNECTED;
+  extern bool syslogEnabled; // Declare as extern if it must be used
+  if (!isConnected || !syslogEnabled) return false;

🏁 Script executed:

#!/bin/bash
# Find where WLED_CONNECTED and syslogEnabled are defined
echo "Searching for WLED_CONNECTED definition:"
rg -A 2 -B 2 "define\s+WLED_CONNECTED" --no-ignore

echo -e "\nSearching for syslogEnabled definition:"
rg -A 2 -B 2 "bool\s+syslogEnabled" --no-ignore

Length of output: 816


Global connectivity and syslog flags are intended—no refactor needed

The use of WLED_CONNECTED and syslogEnabled here follows project conventions for runtime connectivity checks and feature toggles. Extracting them into method parameters would add complexity without improving clarity or testability.

  • WLED_CONNECTED is a macro in wled00/wled.h that evaluates Wi-Fi/Ethernet status at runtime.
  • syslogEnabled is declared as a WLED_GLOBAL bool in wled00/wled.h and controls syslog output globally.

If you need to isolate or mock these for unit tests, wrap them in a thin interface or use test‐level overrides rather than altering production code.

Likely an incorrect or invalid review comment.

@KrX3D
Copy link
Author

KrX3D commented Apr 26, 2025

i could just test it with the RFC 3164 format since my syslog server only works with this. The output of RAW should be the same as the Net Debug.

Maybe someone could look through it since i wasnt really sure about:

wled00/json.cpp:

    #elif defined(WLED_ENABLE_SYSLOG)
    os |= 0x0100;
    if (!syslogEnabled) os &= ~0x0080;

I just took it from the WLED_DEBUG_HOST but im not sure what is does exactly.

also i wansnt really sure where to put this in the setup part

wled00/wled.cpp:

#ifdef WLED_ENABLE_SYSLOG
  // Configure and initialize Syslog client
  Syslog.begin(syslogHost, syslogPort,
    syslogFacility, syslogSeverity, syslogProtocol);
  Syslog.setAppName("WLED");
#endif

i just thought after Wifi would be good

@@ -237,6 +237,59 @@ <h3>Serial</h3>
</select><br>
<i>Keep at 115200 to use Improv. Some boards may not support high rates.</i>
</div>
<h3>Syslog</h3>
Copy link
Collaborator

Choose a reason for hiding this comment

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

this will add size to all builds, not acceptable for a debug function IMHO

Copy link
Member

@netmindz netmindz Apr 26, 2025

Choose a reason for hiding this comment

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

Yeah I would agree that allowing the user to select the facility and level is overkill

Copy link
Author

Choose a reason for hiding this comment

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

this should solve that size problem when not using syslog:

#4664 (comment)

Copy link
Member

Choose a reason for hiding this comment

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

While that is an interesting approach to the problem, I still see no point in allowing the user to define nonsensical values. For example , WLED is not a printer, so what is the point of the user being able to select LPR as the facility.

Copy link
Author

Choose a reason for hiding this comment

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

Hi i just added the full list i found online. So which should i remove/keep? i read somewhere that SYSLOG_LOCAL4 (LOCAL4) is normaly used for user output, thats why i also set is as default.

// Syslog facility codes
#define SYSLOG_KERN     	0  // kernel messages
#define SYSLOG_USER     	1  // user-level messages
#define SYSLOG_MAIL     	2  // mail system
#define SYSLOG_DAEMON   	3  // system daemons
#define SYSLOG_AUTH     	4  // security/authorization messages
#define SYSLOG_SYSLOG   	5  // messages generated internally by syslogd
#define SYSLOG_LPR      	6  // line printer subsystem
#define SYSLOG_NEWS     	7  // network news subsystem
#define SYSLOG_UUCP     	8  // UUCP subsystem
#define SYSLOG_CRON     	9  // clock daemon
#define SYSLOG_AUTHPRIV 	10 // security/authorization messages (private)
#define SYSLOG_FTP      	11 // FTP daemon
#define SYSLOG_NTP      	12 // NTP subsystem (used in some systems)
#define SYSLOG_LOG_AUDIT 	13 // log audit (used in some systems like Linux auditd)
#define SYSLOG_LOG_ALERT 	14 // log alert
#define SYSLOG_CLOCK_DAEMON 15 // clock daemon (alternate)
#define SYSLOG_LOCAL0   	16 // local use 0
#define SYSLOG_LOCAL1   	17 // local use 1
#define SYSLOG_LOCAL2   	18 // local use 2
#define SYSLOG_LOCAL3   	19 // local use 3
#define SYSLOG_LOCAL4   	20 // local use 4
#define SYSLOG_LOCAL5   	21 // local use 5
#define SYSLOG_LOCAL6   	22 // local use 6
#define SYSLOG_LOCAL7   	23 // local use 7

i would think of least those ?

#define SYSLOG_USER     	1  // user-level messages
#define SYSLOG_DAEMON   	3  // system daemons
#define SYSLOG_LOCAL0   	16 // local use 0
#define SYSLOG_LOCAL1   	17 // local use 1
#define SYSLOG_LOCAL2   	18 // local use 2
#define SYSLOG_LOCAL3   	19 // local use 3
#define SYSLOG_LOCAL4   	20 // local use 4
#define SYSLOG_LOCAL5   	21 // local use 5
#define SYSLOG_LOCAL6   	22 // local use 6
#define SYSLOG_LOCAL7   	23 // local use 7

and maybe change th edefault to:

LOCAL0 is reserved for custom applications (i.e. it will never collide with kernel, mail, auth, etc.)

KrX3D and others added 2 commits April 26, 2025 15:03
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
- Add error state tracking to the SyslogPrinter class.
 - configurable buffer size.
That way, anyone can -D SYSLOG_BUFFER_SIZE=256 (or larger) in their build flags to avoid silent truncation.
@DedeHai
Copy link
Collaborator

DedeHai commented Apr 26, 2025

I just took it from the WLED_DEBUG_HOST but im not sure what is does exactly.

it sets or clears bits i.e. flags in os variaable, used in index.js

@blazoncek
Copy link
Collaborator

Looks ok to me (untested), though it is a lot of code for somewhat useful feature. At least it is optional.
By somewhat useful I'm referring to the lack of crash dumps available with network debugging.

@KrX3D
Copy link
Author

KrX3D commented Apr 26, 2025

this will add size to all builds, not acceptable for a debug function IMHO

to not wast size to all builds the html part will now be injected only when

-D WLED_ENABLE_SYSLOG

is used:

070b6b2

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
pio-scripts/inject_syslog_ui.py (3)

2-2: Remove unused import

The sys module is imported but never used in the script.

-import os, shutil, sys
+import os, shutil
🧰 Tools
🪛 Ruff (0.8.2)

2-2: sys imported but unused

Remove unused import: sys

(F401)


120-121: Use context manager for file operations

Opening files without a context manager can lead to resource leaks if exceptions occur.

-            original = open(html_path, 'r', encoding='utf8').read()
-            modified = original
+            with open(html_path, 'r', encoding='utf8') as f:
+                original = f.read()
+                modified = original
🧰 Tools
🪛 Ruff (0.8.2)

120-120: Use a context manager for opening files

(SIM115)


116-151: Consider a more robust approach to detect completed injections

The script assumes that if a backup file exists, the injection has already been completed successfully. This might not be true if a previous run was interrupted or crashed.

Consider adding a more explicit indicator of successful injection, such as checking for the presence of the injected HTML content rather than just relying on the existence of the backup file.

    # backup + inject only once
    if not os.path.exists(bak):
        print("Backing up and injecting Syslog UI...")
        shutil.copyfile(html_path, bak)
        try:
            with open(html_path, 'r', encoding='utf8') as f:
                original = f.read()
                modified = original

            # replace existing section if present
            if '<!-- SYSLOG-START -->' in modified and '<!-- SYSLOG-END -->' in modified:
                start = modified.index('<!-- SYSLOG-START -->')
                end   = modified.index('<!-- SYSLOG-END -->') + len('<!-- SYSLOG-END -->')
                modified = (
                    modified[:start]
                    + '<!-- SYSLOG-START -->\n' + SYSLOG_HTML + '\n<!-- SYSLOG-END -->'
                    + modified[end:]
                )
            else:
                # insert before last <hr>
                idx = modified.rfind('<hr>')
                if idx == -1:
                    print("\033[41mCould not find <hr> to insert Syslog UI!\033[0m")
                    return
                modified = (
                    modified[:idx]
                    + '<!-- SYSLOG-START -->\n' + SYSLOG_HTML + '\n<!-- SYSLOG-END -->\n'
                    + modified[idx:]
                )

            with open(html_path, 'w', encoding='utf8') as f:
                f.write(modified)
            print("\033[42mSyslog UI injected successfully!\033[0m")
        except Exception as e:
            print(f"\033[41mError during injection: {e}\033[0m")
+            # Clean up the backup if injection failed
+            if os.path.exists(bak):
+                os.remove(bak)
    else:
-        print("Backup exists; assume already injected.")
+        # Verify that the injection was actually completed
+        with open(html_path, 'r', encoding='utf8') as f:
+            content = f.read()
+            if '<!-- SYSLOG-START -->' not in content or '<!-- SYSLOG-END -->' not in content:
+                print("Backup exists but injection markers not found. Re-injecting...")
+                os.remove(bak)  # Remove the backup to force re-injection
+                inject_syslog_ui(source, target, env)  # Recursive call to retry injection
+            else:
+                print("Backup exists and injection markers found; already injected.")
🧰 Tools
🪛 Ruff (0.8.2)

120-120: Use a context manager for opening files

(SIM115)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a48b05e and 070b6b2.

📒 Files selected for processing (3)
  • pio-scripts/inject_syslog_ui.py (1 hunks)
  • platformio.ini (1 hunks)
  • wled00/data/settings_sync.htm (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • platformio.ini
🚧 Files skipped from review as they are similar to previous changes (1)
  • wled00/data/settings_sync.htm
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: KrX3D
PR: wled/WLED#4664
File: wled00/syslog.cpp:50-51
Timestamp: 2025-04-26T12:51:04.972Z
Learning: In the WLED codebase, syslog configuration variables (syslogHost, syslogPort, syslogProtocol, syslogFacility, syslogSeverity) are defined as global variables in wled.h and are accessed directly in the SyslogPrinter implementation, rather than being class members.
🪛 Ruff (0.8.2)
pio-scripts/inject_syslog_ui.py

2-2: sys imported but unused

Remove unused import: sys

(F401)


8-8: Undefined name env

(F821)


120-120: Use a context manager for opening files

(SIM115)


167-167: Undefined name env

(F821)


171-171: Undefined name env

(F821)

🔇 Additional comments (5)
pio-scripts/inject_syslog_ui.py (5)

32-32: Consider handling placeholder value

The %SL_port% placeholder is included in the HTML template. Ensure this is properly replaced during runtime by the WLED template system, otherwise users will see the literal placeholder.

Is there a template replacement mechanism in WLED that handles these placeholders? If not, you may need to replace it with a default value or handle it in the script.


5-8: LGTM for SCons environment handling

The import and use of the SCons environment is correct. The static analysis tool incorrectly flagged env as undefined, but this is a standard SCons pattern.

🧰 Tools
🪛 Ruff (0.8.2)

8-8: Undefined name env

(F821)


80-114: Well-structured build flag detection and state tracking

The build flag detection and state tracking logic is robust, with good handling of different flag formats and proper state persistence between builds.


152-165: Effective restoration function

The restoration function correctly handles cleaning up after the build, with proper file permission management and backup removal.


1-171: Overall well-designed injection script

This script provides a clean solution for conditionally including the Syslog UI in the settings page. The approach of injecting at build time keeps the source HTML clean while allowing the feature to be conditionally enabled. The colored console output and detailed progress messages are helpful for debugging.

🧰 Tools
🪛 Ruff (0.8.2)

2-2: sys imported but unused

Remove unused import: sys

(F401)


8-8: Undefined name env

(F821)


120-120: Use a context manager for opening files

(SIM115)


167-167: Undefined name env

(F821)


171-171: Undefined name env

(F821)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
pio-scripts/inject_syslog_ui.py (3)

18-22: Consider adding directory creation check before writing state file

The set_syslog_state function assumes the directory structure exists. If the script runs in a clean environment or the directory is missing, this could fail.

def set_syslog_state(project_dir, enabled):
    state_file = os.path.join(project_dir, "wled00/data/.syslog_state")
+   os.makedirs(os.path.dirname(state_file), exist_ok=True)  # Ensure directory exists
    with open(state_file, 'w') as f:
        f.write("1" if enabled else "0")

158-162: Add retry limit to prevent potential infinite recursion

The current implementation uses recursion without a limit when re-injecting content with missing markers, which could lead to infinite recursion if there's a persistent issue.

-        if '<!-- SYSLOG-START -->' not in content or '<!-- SYSLOG-END -->' not in content:
-            print("Backup exists but SYSLOG markers missing—forcing re-injection.")
-            os.remove(bak)
-            inject_syslog_ui(source, target, env)
+        if '<!-- SYSLOG-START -->' not in content or '<!-- SYSLOG-END -->' not in content:
+            print("Backup exists but SYSLOG markers missing—forcing re-injection.")
+            os.remove(bak)
+            # Pass a retry parameter to prevent infinite recursion
+            if 'retry_count' not in globals():
+                global retry_count
+                retry_count = 0
+            if retry_count < 3:
+                retry_count += 1
+                inject_syslog_ui(source, target, env)
+                retry_count = 0  # Reset on success
+            else:
+                print("\033[41mToo many retry attempts. Manual intervention required.\033[0m")
+                retry_count = 0  # Reset for next run

Alternatively, modify the function signature to accept a retry parameter:

def inject_syslog_ui(source, target, env, retry_count=0):
    # ... existing code ...
    
    # When recursing:
    if retry_count < 3:
        inject_syslog_ui(source, target, env, retry_count + 1)
    else:
        print("\033[41mToo many retry attempts. Manual intervention required.\033[0m")

119-122: Consider handling large files more efficiently

Loading the entire file into memory could be problematic for very large HTML files. Consider reading and processing the file in chunks for better memory efficiency.

For most WLED installations this won't be an issue as the HTML files are relatively small, but it's a good practice to handle files more efficiently, especially in build scripts that might run on resource-constrained systems.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 070b6b2 and cbee84e.

📒 Files selected for processing (1)
  • pio-scripts/inject_syslog_ui.py (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: KrX3D
PR: wled/WLED#4664
File: wled00/syslog.cpp:50-51
Timestamp: 2025-04-26T12:51:04.972Z
Learning: In the WLED codebase, syslog configuration variables (syslogHost, syslogPort, syslogProtocol, syslogFacility, syslogSeverity) are defined as global variables in wled.h and are accessed directly in the SyslogPrinter implementation, rather than being class members.
🪛 Ruff (0.8.2)
pio-scripts/inject_syslog_ui.py

8-8: Undefined name env

(F821)


180-180: Undefined name env

(F821)


184-184: Undefined name env

(F821)

🔇 Additional comments (4)
pio-scripts/inject_syslog_ui.py (4)

32-32: Note about placeholder variable

The %SL_port% placeholder is used here, but this script doesn't replace it with an actual value. This appears to be an intentional design where the placeholder will be processed by WLED's template system when the HTML is served.


88-90: LGTM: Good handling of build flags

Good approach for handling build flags that might be provided either as a list or a string.


174-177: Good file permission handling

Setting the chmod before copying is a nice touch that ensures the file can be written even if permissions were changed.


1-184: Overall feedback on inject_syslog_ui.py

This is a well-structured build script that intelligently handles Syslog UI injection. The approach of backing up the original file, tracking state changes, and verifying markers is robust. The color-coded console output also makes it easy to track what's happening during the build process.

The script correctly integrates with the PlatformIO build system using SCons hooks and handles different build scenarios appropriately.

🧰 Tools
🪛 Ruff (0.8.2)

8-8: Undefined name env

(F821)


180-180: Undefined name env

(F821)


184-184: Undefined name env

(F821)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
pio-scripts/inject_syslog_ui.py (3)

155-156: Add explicit handling for mismatched markers.

Consider adding specific handling for the case where one marker exists but the other doesn't (incomplete previous run). Currently, you check if either marker is missing, but you might want to log which specific marker is missing for easier debugging.

- if '<!-- SYSLOG-START -->' not in content or '<!-- SYSLOG-END -->' not in content:
-     print("Backup exists but SYSLOG markers missing—forcing re-injection.")
+ if '<!-- SYSLOG-START -->' not in content and '<!-- SYSLOG-END -->' not in content:
+     print("Backup exists but both SYSLOG markers missing—forcing re-injection.")
+ elif '<!-- SYSLOG-START -->' not in content:
+     print("Backup exists but SYSLOG-START marker missing—forcing re-injection.")
+ elif '<!-- SYSLOG-END -->' not in content:
+     print("Backup exists but SYSLOG-END marker missing—forcing re-injection.")

159-162: Consider adding delay between retry attempts.

When retrying the injection after failure, consider adding a small delay between attempts to avoid potential file system contention. This could improve reliability when retrying rapidly.

            # only retry up to 3 times
            if retry_count < 3:
+               # Add a small delay before retrying
+               import time
+               time.sleep(0.5 * (retry_count + 1))  # Increasing delay with each retry
                inject_syslog_ui(source, target, env, retry_count + 1)
            else:
                print("\033[41mToo many retry attempts. Manual intervention required.\033[0m")

1-2: Consider adding a brief docstring for maintainability.

While the code is well-structured and self-explanatory, adding a brief docstring at the top of the file would improve maintainability and help future developers understand the script's purpose.

 # pio-scripts/inject_syslog_ui.py
+"""
+PlatformIO build script to conditionally inject Syslog UI elements into the settings HTML file.
+
+This script:
+1. Injects Syslog UI elements when WLED_ENABLE_SYSLOG is defined in build flags
+2. Restores the original HTML file after build completion
+3. Tracks state between builds to force UI rebuilds when necessary
+"""
 import os, shutil
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cbee84e and 3007dcf.

📒 Files selected for processing (2)
  • pio-scripts/inject_syslog_ui.py (1 hunks)
  • wled00/xml.cpp (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • wled00/xml.cpp
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: KrX3D
PR: wled/WLED#4664
File: wled00/syslog.cpp:50-51
Timestamp: 2025-04-26T12:51:04.972Z
Learning: In the WLED codebase, syslog configuration variables (syslogHost, syslogPort, syslogProtocol, syslogFacility, syslogSeverity) are defined as global variables in wled.h and are accessed directly in the SyslogPrinter implementation, rather than being class members.
🪛 Ruff (0.8.2)
pio-scripts/inject_syslog_ui.py

8-8: Undefined name env

(F821)


181-181: Undefined name env

(F821)


185-185: Undefined name env

(F821)

🔇 Additional comments (7)
pio-scripts/inject_syslog_ui.py (7)

1-6: Well-structured script with clear imports and environment handling.

The script properly imports necessary modules and retrieves the PlatformIO environment. The organization is clean and follows best practices for PlatformIO build scripts.


10-22: Good state tracking implementation for build-to-build persistence.

The state tracking functions are well-implemented with proper file handling and error cases. The approach of using a hidden state file to track changes between builds is elegant and efficient.


24-75: Well-structured HTML for the Syslog UI configuration.

The HTML definition provides a comprehensive UI for configuring all syslog parameters (protocol, facility, severity, etc.) with appropriate input types and validation.


87-87: Robust build flag detection handles both spacing variants.

Good job checking for both -D WLED_ENABLE_SYSLOG and -DWLED_ENABLE_SYSLOG variants in the build flags. This ensures the script works correctly regardless of how the flag is specified.


94-101: Effective change detection to force UI rebuilds when needed.

The script intelligently detects state changes between builds and touches the HTML file to force a rebuild when necessary. This ensures the UI stays in sync with the build configuration.


166-179: Good restoration logic with permission handling.

The restoration function correctly handles file permissions (chmod) before copying the backup, which prevents potential permission-related errors. The function is also safely guarded by checking for the backup file's existence.


180-185: Excellent build system integration.

The script properly integrates with the PlatformIO build system by registering a post-action for cleanup and conditionally running the injection only on full builds. This ensures the HTML file is restored to its original state after the build completes.

🧰 Tools
🪛 Ruff (0.8.2)

181-181: Undefined name env

(F821)


185-185: Undefined name env

(F821)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
pio-scripts/inject_syslog_ui.py (2)

97-97: Consider using regex for more robust build flag detection.

The current approach checks for two specific patterns of the define flag. A regex approach might be more robust against variations in spacing or other flag formats.

-    has_syslog = ("-D WLED_ENABLE_SYSLOG" in build_flags or "-DWLED_ENABLE_SYSLOG" in build_flags)
+    import re
+    has_syslog = bool(re.search(r'-D\s*WLED_ENABLE_SYSLOG', build_flags))

155-160: Consider more specific exception handling for file operations.

The current exception handling is generic. It might be beneficial to catch specific exceptions related to file operations separately from other potential issues.

-        except Exception as e:
-            print(f"\033[41mError during injection: {e}\033[0m")
-            # injection failed → remove backup so we'll retry next time
-            if os.path.exists(bak):
-                os.remove(bak)
+        except (IOError, OSError) as e:
+            print(f"\033[41mFile operation error during injection: {e}\033[0m")
+            # injection failed → remove backup so we'll retry next time
+            if os.path.exists(bak):
+                os.remove(bak)
+        except Exception as e:
+            print(f"\033[41mUnexpected error during injection: {e}\033[0m")
+            # injection failed → remove backup so we'll retry next time
+            if os.path.exists(bak):
+                os.remove(bak)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3007dcf and 14910fc.

📒 Files selected for processing (1)
  • pio-scripts/inject_syslog_ui.py (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: KrX3D
PR: wled/WLED#4664
File: wled00/syslog.cpp:50-51
Timestamp: 2025-04-26T12:51:04.972Z
Learning: In the WLED codebase, syslog configuration variables (syslogHost, syslogPort, syslogProtocol, syslogFacility, syslogSeverity) are defined as global variables in wled.h and are accessed directly in the SyslogPrinter implementation, rather than being class members.
🪛 Ruff (0.8.2)
pio-scripts/inject_syslog_ui.py

18-18: Undefined name env

(F821)


194-194: Undefined name env

(F821)


198-198: Undefined name env

(F821)

🔇 Additional comments (7)
pio-scripts/inject_syslog_ui.py (7)

1-19: Well-structured script with clear purpose and good documentation.

The file has a clear header, descriptive docstring, and appropriate imports. The detection of full vs. partial builds is a good optimization to avoid unnecessary processing.

🧰 Tools
🪛 Ruff (0.8.2)

18-18: Undefined name env

(F821)


21-32: Good implementation of state tracking between builds.

The state tracking functions are well-implemented with proper file handling and error management. This approach ensures UI rebuilds only happen when the syslog state changes.


33-85: Complete and well-structured HTML template for Syslog configuration.

The HTML template includes all necessary configuration options for syslog: enable/disable toggle, host, port, protocol selection, facility, and severity levels. The dropdown options cover all standard syslog facilities and severity levels.


126-154: Good implementation of HTML injection with marker-based replacement.

The code properly handles both cases: replacing content between existing markers or inserting at a strategic location. The approach is robust and maintainable.


163-177: Robust verification and retry mechanism for injection failures.

The code verifies that markers are actually present in the file and implements a retry mechanism with incremental delays. This helps recover from potential race conditions or transient file system issues.


179-192: Clean implementation of restore function with proper permission handling.

The restore function properly handles file permissions before copying, which prevents potential permission-related errors. The backup file is correctly removed after restoration.


193-198: Good integration with PlatformIO build process.

The script properly integrates with the PlatformIO build process by registering the restore function as a post-action and conditionally running the injection only on full builds.

🧰 Tools
🪛 Ruff (0.8.2)

194-194: Undefined name env

(F821)


198-198: Undefined name env

(F821)

Copy link
Member

@netmindz netmindz left a comment

Choose a reason for hiding this comment

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

Please remove any configuration options that do not add value

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants