Compare commits
10
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d3d3817ae2 | ||
|
|
cb65332eb4 | ||
|
|
9defb88edd | ||
|
|
15a9db7342 | ||
|
|
a39d9d40cf | ||
|
|
dc7cf99926 | ||
|
|
6f636f88ed | ||
|
|
93e54ce764 | ||
|
|
da076a19e6 | ||
|
|
c6848f6876 |
No files matched your search
@@ -1,32 +1,27 @@
|
|||||||
# ESP32 ESP-IDF component for Syslog UDP client
|
# ESP32 ESP-IDF component for syslog (UDP client)
|
||||||
|
|
||||||
## Wiki
|
|
||||||
|
|
||||||
[EN](WIKI_EN.md) | [RU](WIKI_RU.md)
|
|
||||||
|
|
||||||
## Tested on
|
|
||||||
|
|
||||||
1. [ESP-IDF v6.0.0](https://docs.espressif.com/projects/esp-idf/en/v6.0/esp32/index.html)
|
|
||||||
|
|
||||||
## SAST Tools
|
|
||||||
|
|
||||||
[PVS-Studio](https://pvs-studio.com/pvs-studio/?utm_source=website&utm_medium=github&utm_campaign=open_source) — static analyzer for C, C++, C#, and Java code.
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
1. Support for all standard syslog facility codes (0-23) per RFC 5424
|
1. Support for all standard syslog facility codes (0-23) per RFC 5424.
|
||||||
2. Support for all standard syslog severity levels (0-7) per RFC 5424
|
2. Support for all standard syslog severity levels (0-7) per RFC 5424.
|
||||||
3. RFC 5424 format message generation with priority calculation
|
3. RFC 5424 format message generation with priority calculation.
|
||||||
4. Thread-safe initialization and deinitialization
|
4. Thread-safe initialization and deinitialization.
|
||||||
5. MALLOC_CAP_8BIT memory allocation for DMA compatibility
|
5. Memory allocation with MALLOC_CAP_8BIT for DMA compatibility.
|
||||||
|
6. Short messages use stack buffer, longer ones fall back to heap allocation.
|
||||||
|
|
||||||
|
## Attention
|
||||||
|
|
||||||
|
1. Network connection must be established before calling zh_syslog_init.
|
||||||
|
2. UDP is connectionless and message delivery is not guaranteed.
|
||||||
|
3. zh_syslog_send is not thread-safe, caller must ensure mutual exclusion.
|
||||||
|
|
||||||
## Using
|
## Using
|
||||||
|
|
||||||
In an existing project, run the following command to install the components:
|
In an existing project, run the following command to install the component:
|
||||||
|
|
||||||
```text
|
```bash
|
||||||
cd ../your_project/components
|
cd ../your_project/components
|
||||||
git clone https://github.com/aZholtikov/zh_syslog.git
|
git clone https://github.com/aZholtikov/zh_syslog
|
||||||
```
|
```
|
||||||
|
|
||||||
In the application, add the component:
|
In the application, add the component:
|
||||||
@@ -37,8 +32,144 @@ In the application, add the component:
|
|||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
See Wiki [EN](WIKI_EN.md#usage-examples) | [RU](WIKI_RU.md#примеры-использования)
|
### Basic Example
|
||||||
|
|
||||||
## Note
|
```c
|
||||||
|
#include "zh_syslog.h"
|
||||||
|
|
||||||
Messages are built using the format defined in [RFC 5424](https://datatracker.ietf.org/doc/html/rfc5424).
|
void app_main(void)
|
||||||
|
{
|
||||||
|
esp_log_level_set("zh_syslog", ESP_LOG_ERROR);
|
||||||
|
zh_syslog_init_config_t config = ZH_SYSLOG_INIT_CONFIG_DEFAULT();
|
||||||
|
strcpy(config.syslog_ip, "192.168.1.100");
|
||||||
|
esp_err_t ret = zh_syslog_init(&config);
|
||||||
|
if (ret != ESP_OK)
|
||||||
|
{
|
||||||
|
printf("Syslog initialization error\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ret = zh_syslog_send(ZH_USER, ZH_INFO, "my_device", "my_app", "Hello Syslog");
|
||||||
|
if (ret == ESP_OK)
|
||||||
|
{
|
||||||
|
printf("Message sent\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Send error: %s\n", esp_err_to_name(ret));
|
||||||
|
}
|
||||||
|
zh_syslog_deinit();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Facility and Severity Example
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include "zh_syslog.h"
|
||||||
|
|
||||||
|
void app_main(void)
|
||||||
|
{
|
||||||
|
esp_log_level_set("zh_syslog", ESP_LOG_ERROR);
|
||||||
|
zh_syslog_init_config_t config = ZH_SYSLOG_INIT_CONFIG_DEFAULT();
|
||||||
|
strcpy(config.syslog_ip, "192.168.1.100");
|
||||||
|
esp_err_t ret = zh_syslog_init(&config);
|
||||||
|
if (ret != ESP_OK)
|
||||||
|
{
|
||||||
|
printf("Syslog initialization error\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ret = zh_syslog_send(ZH_KERN, ZH_ERR, "my_device", "my_app", "Kernel error");
|
||||||
|
if (ret == ESP_OK)
|
||||||
|
{
|
||||||
|
printf("Kernel error sent\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Send error: %s\n", esp_err_to_name(ret));
|
||||||
|
}
|
||||||
|
ret = zh_syslog_send(ZH_USER, ZH_WARNING, "my_device", "my_app", "User warning");
|
||||||
|
if (ret == ESP_OK)
|
||||||
|
{
|
||||||
|
printf("User warning sent\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Send error: %s\n", esp_err_to_name(ret));
|
||||||
|
}
|
||||||
|
zh_syslog_deinit();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Long Message Example
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include "zh_syslog.h"
|
||||||
|
|
||||||
|
void app_main(void)
|
||||||
|
{
|
||||||
|
esp_log_level_set("zh_syslog", ESP_LOG_ERROR);
|
||||||
|
zh_syslog_init_config_t config = ZH_SYSLOG_INIT_CONFIG_DEFAULT();
|
||||||
|
strcpy(config.syslog_ip, "192.168.1.100");
|
||||||
|
esp_err_t ret = zh_syslog_init(&config);
|
||||||
|
if (ret != ESP_OK)
|
||||||
|
{
|
||||||
|
printf("Syslog initialization error\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
char long_message[512];
|
||||||
|
memset(long_message, 'A', sizeof(long_message) - 1);
|
||||||
|
long_message[sizeof(long_message) - 1] = '\0';
|
||||||
|
ret = zh_syslog_send(ZH_USER, ZH_INFO, "my_device", "my_app", long_message);
|
||||||
|
if (ret == ESP_OK)
|
||||||
|
{
|
||||||
|
printf("Long message sent\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Send error: %s\n", esp_err_to_name(ret));
|
||||||
|
}
|
||||||
|
zh_syslog_deinit();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Deinitialization Example
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include "zh_syslog.h"
|
||||||
|
|
||||||
|
void app_main(void)
|
||||||
|
{
|
||||||
|
esp_log_level_set("zh_syslog", ESP_LOG_ERROR);
|
||||||
|
zh_syslog_init_config_t config = ZH_SYSLOG_INIT_CONFIG_DEFAULT();
|
||||||
|
strcpy(config.syslog_ip, "192.168.1.100");
|
||||||
|
esp_err_t ret = zh_syslog_init(&config);
|
||||||
|
if (ret != ESP_OK)
|
||||||
|
{
|
||||||
|
printf("Syslog initialization error\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ret = zh_syslog_send(ZH_USER, ZH_DEBUG, "my_device", "my_app", "Debug message");
|
||||||
|
if (ret == ESP_OK)
|
||||||
|
{
|
||||||
|
printf("Message sent\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Send error: %s\n", esp_err_to_name(ret));
|
||||||
|
}
|
||||||
|
ret = zh_syslog_deinit();
|
||||||
|
if (ret == ESP_OK)
|
||||||
|
{
|
||||||
|
printf("Syslog deinitialized\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Deinit error: %s\n", esp_err_to_name(ret));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
-415
@@ -1,415 +0,0 @@
|
|||||||
# zh_syslog — Syslog UDP Client Component for ESP-IDF
|
|
||||||
|
|
||||||
## Table of Contents
|
|
||||||
|
|
||||||
- [Overview](#overview)
|
|
||||||
- [Features](#features)
|
|
||||||
- [Installation](#installation)
|
|
||||||
- [API Reference](#api-reference)
|
|
||||||
- [Usage Examples](#usage-examples)
|
|
||||||
- [Technical Specifications](#technical-specifications)
|
|
||||||
- [Error Codes](#error-codes)
|
|
||||||
- [Contributing](#contributing)
|
|
||||||
- [License](#license)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
`zh_syslog` is a lightweight syslog UDP client library for ESP-IDF (Espressif IoT Development Framework). It provides an implementation of RFC 5424-compatible syslog message formatting and transmission over UDP datagrams. The library is designed specifically for ESP32/ESP-IDF platforms and integrates seamlessly with FreeRTOS-based applications.
|
|
||||||
|
|
||||||
The library enables ESP32 devices to send structured log messages to a remote syslog server, facilitating centralized log management and monitoring in IoT deployments. Messages are formatted according to the RFC 5424 standard, supporting facility codes (0-23) and severity levels (0-7) for precise log categorization.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
- **RFC 5424 Compliance**: Messages are formatted according to the RFC 5424 syslog standard
|
|
||||||
- **Standard Facility Codes**: Support for all 24 standard syslog facility codes (KERN, USER, DAEMON, LOCAL0-LOCAL7, etc.)
|
|
||||||
- **Severity Levels**: Support for all 8 standard syslog severity levels (EMERG, ALERT, CRIT, ERR, WARNING, NOTICE, INFO, DEBUG)
|
|
||||||
- **UDP Transport**: Uses datagram sockets for efficient log transmission
|
|
||||||
- **DMA-Compatible Memory**: Utilizes MALLOC_CAP_8BIT allocations for potential DMA usage
|
|
||||||
- **Structured Logging**: Includes hostname, app name, and message fields per RFC 5424
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
Navigate to your project's components directory:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd ../your_project/components
|
|
||||||
```
|
|
||||||
|
|
||||||
Clone the repository:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git clone https://github.com/aZholtikov/zh_syslog
|
|
||||||
```
|
|
||||||
|
|
||||||
In your application, include the header:
|
|
||||||
|
|
||||||
```c
|
|
||||||
#include "zh_syslog.h"
|
|
||||||
```
|
|
||||||
|
|
||||||
The component will be automatically built with your project.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## API Reference
|
|
||||||
|
|
||||||
### zh_syslog_init_config_t Structure
|
|
||||||
|
|
||||||
Configuration structure for syslog client initialization.
|
|
||||||
|
|
||||||
**Fields (internal):**
|
|
||||||
|
|
||||||
| Field | Type | Description |
|
|
||||||
| ------ | ------ | ---------- |
|
|
||||||
| `syslog_ip` | `char[16]` | Syslog server IPv4 address as a null-terminated string (e.g., "192.168.1.1"). Maximum 15 characters plus null terminator. |
|
|
||||||
| `syslog_port` | `uint32_t` | Syslog server UDP port number (typically 514). |
|
|
||||||
|
|
||||||
**Note:** IP address must be a valid IPv4 string. Port should be within valid range (standard syslog port is 514).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### zh_syslog_facility_code_t Enum
|
|
||||||
|
|
||||||
Standard syslog facility codes per RFC 5424 (0-23).
|
|
||||||
|
|
||||||
**Values:**
|
|
||||||
|
|
||||||
| Value | Enum | Description |
|
|
||||||
| ------- | ------ | ------------- |
|
|
||||||
| 0 | `ZH_KERN` | Kernel messages |
|
|
||||||
| 1 | `ZH_USER` | User-level messages |
|
|
||||||
| 2 | `ZH_MAIL` | Mail system |
|
|
||||||
| 3 | `ZH_DAEMON` | System daemons |
|
|
||||||
| 4 | `ZH_AUTH` | Security/authorization messages |
|
|
||||||
| 5 | `ZH_SYSLOG` | Messages from syslogd internally |
|
|
||||||
| 6 | `ZH_LPR` | Line printer subsystem |
|
|
||||||
| 7 | `ZH_NEWS` | Network news subsystem |
|
|
||||||
| 8 | `ZH_UUCP` | UUCP subsystem |
|
|
||||||
| 9 | `ZH_CRON` | Cron subsystem |
|
|
||||||
| 10 | `ZH_AUTHPRIV` | Security/authorization messages (private) |
|
|
||||||
| 11 | `ZH_FTP` | FTP daemon |
|
|
||||||
| 12 | `ZH_NTP` | NTP subsystem |
|
|
||||||
| 13 | `ZH_SECURITY` | Log audit |
|
|
||||||
| 14 | `ZH_CONSOLE` | Log alert |
|
|
||||||
| 15 | `ZH_SOLARIS_CRON` | Scheduling daemon |
|
|
||||||
| 16-23 | `ZH_LOCAL0`-`ZH_LOCAL7` | Local/custom use facilities |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### zh_syslog_severity_code_t Enum
|
|
||||||
|
|
||||||
Standard syslog severity codes per RFC 5424 (0-7).
|
|
||||||
|
|
||||||
**Values:**
|
|
||||||
|
|
||||||
| Value | Enum | Description |
|
|
||||||
| ------- | ------ | ------------- |
|
|
||||||
| 0 | `ZH_EMERG` | System is unusable |
|
|
||||||
| 1 | `ZH_ALERT` | Action must be taken immediately |
|
|
||||||
| 2 | `ZH_CRIT` | Critical conditions |
|
|
||||||
| 3 | `ZH_ERR` | Error conditions |
|
|
||||||
| 4 | `ZH_WARNING` | Warning conditions |
|
|
||||||
| 5 | `ZH_NOTICE` | Normal but significant condition |
|
|
||||||
| 6 | `ZH_INFO` | Informational messages |
|
|
||||||
| 7 | `ZH_DEBUG` | Debug-level messages |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### zh_syslog_init()
|
|
||||||
|
|
||||||
Initializes the syslog client by creating a UDP socket and configuring the destination server address.
|
|
||||||
|
|
||||||
**Parameters:**
|
|
||||||
|
|
||||||
- `config` - Pointer to `zh_syslog_init_config_t` with syslog server address and port. Can point to a temporary variable.
|
|
||||||
|
|
||||||
**Returns:**
|
|
||||||
|
|
||||||
- `ESP_OK` - Success
|
|
||||||
- `ESP_ERR_INVALID_ARG` - Config pointer is NULL
|
|
||||||
- `ESP_FAIL` - Socket creation failed
|
|
||||||
|
|
||||||
**Example:**
|
|
||||||
|
|
||||||
```c
|
|
||||||
zh_syslog_init_config_t config = ZH_SYSLOG_INIT_CONFIG_DEFAULT();
|
|
||||||
strcpy(config.syslog_ip, "192.168.1.100");
|
|
||||||
esp_err_t ret = zh_syslog_init(&config);
|
|
||||||
if (ret != ESP_OK) {
|
|
||||||
// Handle initialization error
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Note:** Network connection must be established before calling this function. The config pointer can be temporary. Must not be NULL
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### zh_syslog_deinit()
|
|
||||||
|
|
||||||
Deinitializes the syslog client and releases resources.
|
|
||||||
|
|
||||||
**Returns:**
|
|
||||||
|
|
||||||
- `ESP_OK` - Success
|
|
||||||
- `ESP_ERR_INVALID_STATE` - Client was not initialized
|
|
||||||
|
|
||||||
**Note:** After calling this function, `zh_syslog_init()` must be called again before any subsequent `zh_syslog_send()` calls.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### zh_syslog_send()
|
|
||||||
|
|
||||||
Sends a formatted syslog message to the configured server.
|
|
||||||
|
|
||||||
**Parameters:**
|
|
||||||
|
|
||||||
- `facility` - Syslog facility code (0-23) from `zh_syslog_facility_code_t`
|
|
||||||
- `severity` - Syslog severity code (0-7) from `zh_syslog_severity_code_t`
|
|
||||||
- `hostname` - Pointer to device hostname (alphanumeric characters only, no spaces). Must not be NULL
|
|
||||||
- `app_name` - Pointer to application name (alphanumeric characters only, no spaces). Must not be NULL
|
|
||||||
- `message` - Pointer to the message payload string. Must not be NULL
|
|
||||||
|
|
||||||
**Returns:**
|
|
||||||
|
|
||||||
- `ESP_OK` - Success
|
|
||||||
- `ESP_ERR_INVALID_ARG` - hostname, app_name, or message is NULL
|
|
||||||
- `ESP_ERR_INVALID_STATE` - Client was not initialized
|
|
||||||
- `ESP_ERR_NO_MEM` - Memory allocation failed (1024 bytes payload buffer)
|
|
||||||
- `ESP_FAIL` - UDP send operation failed
|
|
||||||
|
|
||||||
**Example:**
|
|
||||||
|
|
||||||
```c
|
|
||||||
zh_syslog_send(ZH_USER, ZH_INFO, "esp32_device", "my_app", "System started");
|
|
||||||
```
|
|
||||||
|
|
||||||
**Note:** This function is not thread-safe. Caller must ensure mutual exclusion if multiple tasks may call this function concurrently. Message format follows RFC 5424: `<priority>1 timestamp hostname app-name procid msgid - message`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Usage Examples
|
|
||||||
|
|
||||||
### Basic Example: Initialize and Send Messages
|
|
||||||
|
|
||||||
```c
|
|
||||||
#include "zh_syslog.h"
|
|
||||||
|
|
||||||
void app_main(void)
|
|
||||||
{
|
|
||||||
esp_log_level_set("zh_syslog", ESP_LOG_ERROR);
|
|
||||||
// Initialize configuration with defaults
|
|
||||||
zh_syslog_init_config_t config = ZH_SYSLOG_INIT_CONFIG_DEFAULT();
|
|
||||||
strcpy(config.syslog_ip, "192.168.1.100"); // Set syslog server IP
|
|
||||||
|
|
||||||
// Initialize syslog client
|
|
||||||
esp_err_t ret = zh_syslog_init(&config);
|
|
||||||
if (ret != ESP_OK)
|
|
||||||
{
|
|
||||||
printf("Syslog initialization failed: %s\n", esp_err_to_name(ret));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send informational message
|
|
||||||
zh_syslog_send(ZH_USER, ZH_INFO, "my_device", "my_app", "Application started");
|
|
||||||
|
|
||||||
// Send warning message
|
|
||||||
zh_syslog_send(ZH_USER, ZH_WARNING, "my_device", "my_app", "Low battery");
|
|
||||||
|
|
||||||
// Send error message
|
|
||||||
zh_syslog_send(ZH_KERN, ZH_ERR, "my_device", "kernel", "Disk read error");
|
|
||||||
|
|
||||||
// Deinitialize when done
|
|
||||||
zh_syslog_deinit();
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Example: Wi-Fi Integration with Periodic Logging
|
|
||||||
|
|
||||||
```c
|
|
||||||
#include "nvs_flash.h"
|
|
||||||
#include "esp_netif.h"
|
|
||||||
#include "esp_wifi.h"
|
|
||||||
#include "esp_event.h"
|
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "freertos/event_groups.h"
|
|
||||||
#include "zh_syslog.h"
|
|
||||||
|
|
||||||
#define WIFI_SSID "your_ssid"
|
|
||||||
#define WIFI_PASS "your_password"
|
|
||||||
#define WIFI_CONNECT_SUCCESS BIT0
|
|
||||||
|
|
||||||
static EventGroupHandle_t s_event_group;
|
|
||||||
static const int WIFI_CONNECTED_BIT = BIT0;
|
|
||||||
|
|
||||||
static void wifi_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data);
|
|
||||||
|
|
||||||
void app_main(void)
|
|
||||||
{
|
|
||||||
esp_log_level_set("zh_syslog", ESP_LOG_ERROR);
|
|
||||||
nvs_flash_init();
|
|
||||||
esp_netif_init();
|
|
||||||
esp_event_loop_create_default();
|
|
||||||
esp_netif_create_default_wifi_sta();
|
|
||||||
|
|
||||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
|
||||||
esp_wifi_init(&cfg);
|
|
||||||
|
|
||||||
wifi_config_t wifi_config = {
|
|
||||||
.sta = {
|
|
||||||
.ssid = WIFI_SSID,
|
|
||||||
.password = WIFI_PASS,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
esp_wifi_set_mode(WIFI_MODE_STA);
|
|
||||||
esp_wifi_set_config(WIFI_IF_STA, &wifi_config);
|
|
||||||
esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL, NULL);
|
|
||||||
esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &wifi_event_handler, NULL, NULL);
|
|
||||||
esp_wifi_start();
|
|
||||||
|
|
||||||
s_event_group = xEventGroupCreate();
|
|
||||||
xEventGroupWaitBits(s_event_group, WIFI_CONNECTED_BIT, pdFALSE, pdTRUE, portMAX_DELAY);
|
|
||||||
|
|
||||||
// Initialize syslog after Wi-Fi connection
|
|
||||||
zh_syslog_init_config_t config = ZH_SYSLOG_INIT_CONFIG_DEFAULT();
|
|
||||||
strcpy(config.syslog_ip, "192.168.1.100");
|
|
||||||
zh_syslog_init(&config);
|
|
||||||
|
|
||||||
// Send periodic log messages
|
|
||||||
for (int i = 0; i < 10; i++) {
|
|
||||||
char msg[64];
|
|
||||||
snprintf(msg, sizeof(msg), "Heartbeat #%d", i + 1);
|
|
||||||
zh_syslog_send(ZH_USER, ZH_INFO, "esp32_sensor", "logger", msg);
|
|
||||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
|
||||||
}
|
|
||||||
|
|
||||||
zh_syslog_deinit();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void wifi_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
|
|
||||||
{
|
|
||||||
if (event_id == IP_EVENT_STA_GOT_IP)
|
|
||||||
{
|
|
||||||
xEventGroupSetBits(s_event_group, WIFI_CONNECTED_BIT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Example: Using Facility and Severity Codes
|
|
||||||
|
|
||||||
```c
|
|
||||||
#include "zh_syslog.h"
|
|
||||||
|
|
||||||
void app_main(void)
|
|
||||||
{
|
|
||||||
esp_log_level_set("zh_syslog", ESP_LOG_ERROR);
|
|
||||||
zh_syslog_init_config_t config = ZH_SYSLOG_INIT_CONFIG_DEFAULT();
|
|
||||||
strcpy(config.syslog_ip, "192.168.1.100");
|
|
||||||
zh_syslog_init(&config);
|
|
||||||
|
|
||||||
// Kernel critical error
|
|
||||||
zh_syslog_send(ZH_KERN, ZH_CRIT, "esp32", "kernel", "Out of memory");
|
|
||||||
|
|
||||||
// User application warning
|
|
||||||
zh_syslog_send(ZH_USER, ZH_WARNING, "esp32", "app", "Sensor reading timeout");
|
|
||||||
|
|
||||||
// Auth subsystem notice
|
|
||||||
zh_syslog_send(ZH_AUTH, ZH_NOTICE, "esp32", "auth", "User login successful");
|
|
||||||
|
|
||||||
// Local facility for custom logging
|
|
||||||
zh_syslog_send(ZH_LOCAL0, ZH_DEBUG, "esp32", "debugger", "Variable state: 0x1234");
|
|
||||||
|
|
||||||
zh_syslog_deinit();
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Technical Specifications
|
|
||||||
|
|
||||||
| Parameter | Value |
|
|
||||||
| ----------- | ------- |
|
|
||||||
| **Message Size** | 1024 bytes (fixed buffer) |
|
|
||||||
| **Transport Protocol** | UDP (SOCK_DGRAM) |
|
|
||||||
| **Default Port** | 514 |
|
|
||||||
| **Format Standard** | RFC 5424 |
|
|
||||||
| **Memory Allocation** | heap_caps_calloc (MALLOC_CAP_8BIT) |
|
|
||||||
| **Thread Safety** | Not thread-safe (caller responsibility) |
|
|
||||||
| **ESP-IDF Version** | >= 5.0 |
|
|
||||||
| **Platform** | ESP32 series |
|
|
||||||
| **Language** | C (C99) |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Error Codes
|
|
||||||
|
|
||||||
| Error Code | Description |
|
|
||||||
| ------------ | ------------- |
|
|
||||||
| `ESP_OK` | Operation successful |
|
|
||||||
| `ESP_ERR_INVALID_ARG` | Invalid argument (NULL config pointer, NULL hostname/app_name/message) |
|
|
||||||
| `ESP_ERR_INVALID_STATE` | Client not initialized (zh_syslog_init not called) |
|
|
||||||
| `ESP_ERR_NO_MEM` | Memory allocation failed (out of memory for 1024-byte buffer) |
|
|
||||||
| `ESP_FAIL` | Socket creation failed or UDP send operation failed |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
Contributions are welcome! To contribute:
|
|
||||||
|
|
||||||
1. Fork the repository
|
|
||||||
2. Create a feature branch (`git checkout -b feature/AmazingFeature`)
|
|
||||||
3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
|
|
||||||
4. Push to the branch (`git push origin feature/AmazingFeature`)
|
|
||||||
5. Open a Pull Request
|
|
||||||
|
|
||||||
Please ensure your code follows the existing style and includes appropriate documentation.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
This project is licensed under the Apache License, Version 2.0 - see the [LICENSE](LICENSE) file for details.
|
|
||||||
|
|
||||||
### Apache License, Version 2.0
|
|
||||||
|
|
||||||
Copyright (c) 2026 Alexey Zholtikov
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Additional Notes
|
|
||||||
|
|
||||||
- **UDP Reliability**: This library uses UDP which does not guarantee message delivery. For reliable delivery, implement application-level acknowledgment.
|
|
||||||
- **Performance**: O(n) for message formatting (n = message length). Send operation is blocking.
|
|
||||||
- **Best Practices**:
|
|
||||||
- Always check return values from zh_syslog_init() and zh_syslog_send()
|
|
||||||
- Call zh_syslog_deinit() before application exit or module unload
|
|
||||||
- Use facility codes to categorize log sources (KERN for OS, USER for app, LOCAL0-7 for custom)
|
|
||||||
- Keep hostname and app_name alphanumeric (no spaces) per RFC 5424
|
|
||||||
- Set appropriate log level filtering on the syslog server to avoid excessive traffic
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*Generated for zh_syslog v1.0.0*
|
|
||||||
-415
@@ -1,415 +0,0 @@
|
|||||||
# zh_syslog — Компонент syslog UDP клиента для ESP-IDF
|
|
||||||
|
|
||||||
## Содержание
|
|
||||||
|
|
||||||
- [Обзор](#обзор)
|
|
||||||
- [Возможности](#возможности)
|
|
||||||
- [Установка](#установка)
|
|
||||||
- [Справочник API](#справочник-api)
|
|
||||||
- [Примеры использования](#примеры-использования)
|
|
||||||
- [Технические характеристики](#технические-характеристики)
|
|
||||||
- [Коды ошибок](#коды-ошибок)
|
|
||||||
- [Вклад в проект](#вклад-в-проект)
|
|
||||||
- [Лицензия](#лицензия)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Обзор
|
|
||||||
|
|
||||||
`zh_syslog` — это легковесная библиотека syslog UDP клиента для ESP-IDF (Espressif IoT Development Framework). Она предоставляет реализацию формирования и передачи syslog-сообщений совместимых со стандартом RFC 5424 через UDP дейтаграммы. Библиотека разработана специально для платформ ESP32/ESP-IDF и бесшовно интегрируется с приложениями на базе FreeRTOS.
|
|
||||||
|
|
||||||
Библиотека позволяет устройствам ESP32 отправлять структурированные журнальные сообщения на удалённый syslog-сервер, что способствует централизованному управлению журналами и мониторингу в IoT-развертываниях. Сообщения форматируются в соответствии со стандартом RFC 5424, поддерживая коды facility (0-23) и уровни важности (0-7) для точной категоризации журналов.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Возможности
|
|
||||||
|
|
||||||
- **Соответствие RFC 5424**: Сообщения форматируются в соответствии со стандартом syslog RFC 5424
|
|
||||||
- **Стандартные коды Facility**: Поддержка всех 24 стандартных кодов facility syslog (KERN, USER, DAEMON, LOCAL0-LOCAL7 и т.д.)
|
|
||||||
- **Уровни важности**: Поддержка всех 8 стандартных уровней severity syslog (EMERG, ALERT, CRIT, ERR, WARNING, NOTICE, INFO, DEBUG)
|
|
||||||
- **UDP транспорт**: Использует дейтаграммные сокеты для эффективной передачи журналов
|
|
||||||
- **Память совместимая с DMA**: Использует выделения MALLOC_CAP_8BIT для потенциального использования DMA
|
|
||||||
- **Структурированное логирование**: Включает поля hostname, app name и message в соответствии с RFC 5424
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Установка
|
|
||||||
|
|
||||||
Перейдите в каталог компонентов вашего проекта:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd ../ваш_проект/components
|
|
||||||
```
|
|
||||||
|
|
||||||
Клонируйте репозиторий:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git clone https://github.com/aZholtikov/zh_syslog
|
|
||||||
```
|
|
||||||
|
|
||||||
В вашем приложении подключите заголовочный файл:
|
|
||||||
|
|
||||||
```c
|
|
||||||
#include "zh_syslog.h"
|
|
||||||
```
|
|
||||||
|
|
||||||
Компонент будет автоматически собран вместе с вашим проектом.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Справочник API
|
|
||||||
|
|
||||||
### Структура zh_syslog_init_config_t
|
|
||||||
|
|
||||||
Структура конфигурации для инициализации syslog клиента.
|
|
||||||
|
|
||||||
**Поля (внутренние):**
|
|
||||||
|
|
||||||
| Поле | Тип | Описание |
|
|
||||||
| ------ | ------ | ---------- |
|
|
||||||
| `syslog_ip` | `char[16]` | IPv4-адрес syslog сервера в виде нуль-терминированной строки (например, "192.168.1.1"). Максимум 15 символов плюс нуль-терминатор. |
|
|
||||||
| `syslog_port` | `uint32_t` | UDP-порт syslog сервера (обычно 514). |
|
|
||||||
|
|
||||||
**Примечание:** IP-адрес должен быть валидной IPv4-строкой. Порт должен быть в допустимом диапазоне (стандартный порт syslog — 514).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Перечисление zh_syslog_facility_code_t
|
|
||||||
|
|
||||||
Стандартные коды facility syslog в соответствии с RFC 5424 (0-23).
|
|
||||||
|
|
||||||
**Значения:**
|
|
||||||
|
|
||||||
| Значение | Перечисление | Описание |
|
|
||||||
| ---------- | -------------- | ---------- |
|
|
||||||
| 0 | `ZH_KERN` | Сообщения ядра |
|
|
||||||
| 1 | `ZH_USER` | Пользовательские сообщения |
|
|
||||||
| 2 | `ZH_MAIL` | Почтовая система |
|
|
||||||
| 3 | `ZH_DAEMON` | Системные демоны |
|
|
||||||
| 4 | `ZH_AUTH` | Сообщения безопасности/авторизации |
|
|
||||||
| 5 | `ZH_SYSLOG` | Сообщения от самого syslogd |
|
|
||||||
| 6 | `ZH_LPR` | Подсистема принтеров |
|
|
||||||
| 7 | `ZH_NEWS` | Сетевая подсистема новостей |
|
|
||||||
| 8 | `ZH_UUCP` | Подсистема UUCP |
|
|
||||||
| 9 | `ZH_CRON` | Подсистема cron |
|
|
||||||
| 10 | `ZH_AUTHPRIV` | Сообщения безопасности (приватные) |
|
|
||||||
| 11 | `ZH_FTP` | FTP демон |
|
|
||||||
| 12 | `ZH_NTP` | Подсистема NTP |
|
|
||||||
| 13 | `ZH_SECURITY` | Журнал аудита |
|
|
||||||
| 14 | `ZH_CONSOLE` | Журнал уведомлений |
|
|
||||||
| 15 | `ZH_SOLARIS_CRON` | Планировщик задач |
|
|
||||||
| 16-23 | `ZH_LOCAL0`-`ZH_LOCAL7` | Локальное/пользовательское использование |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Перечисление zh_syslog_severity_code_t
|
|
||||||
|
|
||||||
Стандартные коды severity syslog в соответствии с RFC 5424 (0-7).
|
|
||||||
|
|
||||||
**Значения:**
|
|
||||||
|
|
||||||
| Значение | Перечисление | Описание |
|
|
||||||
| ---------- | -------------- | ---------- |
|
|
||||||
| 0 | `ZH_EMERG` | Система неработоспособна |
|
|
||||||
| 1 | `ZH_ALERT` | Необходимо немедленное действие |
|
|
||||||
| 2 | `ZH_CRIT` | Критические условия |
|
|
||||||
| 3 | `ZH_ERR` | Ошибки |
|
|
||||||
| 4 | `ZH_WARNING` | Предупреждения |
|
|
||||||
| 5 | `ZH_NOTICE` | Обычные, но значимые условия |
|
|
||||||
| 6 | `ZH_INFO` | Информационные сообщения |
|
|
||||||
| 7 | `ZH_DEBUG` | Сообщения отладки |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### zh_syslog_init()
|
|
||||||
|
|
||||||
Инициализирует syslog клиент путём создания UDP сокета и настройки адреса целевого сервера.
|
|
||||||
|
|
||||||
**Параметры:**
|
|
||||||
|
|
||||||
- `config` — Указатель на `zh_syslog_init_config_t` с адресом и портом syslog сервера. Может указывать на временную переменную. Не должен быть NULL
|
|
||||||
|
|
||||||
**Возвращает:**
|
|
||||||
|
|
||||||
- `ESP_OK` — Успех
|
|
||||||
- `ESP_ERR_INVALID_ARG` — Указатель config равен NULL
|
|
||||||
- `ESP_FAIL` — Создание сокета не удалось
|
|
||||||
|
|
||||||
**Пример:**
|
|
||||||
|
|
||||||
```c
|
|
||||||
zh_syslog_init_config_t config = ZH_SYSLOG_INIT_CONFIG_DEFAULT();
|
|
||||||
strcpy(config.syslog_ip, "192.168.1.100");
|
|
||||||
esp_err_t ret = zh_syslog_init(&config);
|
|
||||||
if (ret != ESP_OK) {
|
|
||||||
// Обработка ошибки инициализации
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Примечание:** Подключение к сети должно быть установлено перед вызовом этой функции. Указатель config может быть временным.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### zh_syslog_deinit()
|
|
||||||
|
|
||||||
Деинициализирует syslog клиент и освобождает ресурсы.
|
|
||||||
|
|
||||||
**Возвращает:**
|
|
||||||
|
|
||||||
- `ESP_OK` — Успех
|
|
||||||
- `ESP_ERR_INVALID_STATE` — Клиент не был инициализирован
|
|
||||||
|
|
||||||
**Примечание:** После вызова этой функции `zh_syslog_init()` должна быть вызвана заново перед любыми последующими вызовами `zh_syslog_send()`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### zh_syslog_send()
|
|
||||||
|
|
||||||
Отправляет отформатированное syslog-сообщение на настроенный сервер.
|
|
||||||
|
|
||||||
**Параметры:**
|
|
||||||
|
|
||||||
- `facility` — Код facility syslog (0-23) из `zh_syslog_facility_code_t`
|
|
||||||
- `severity` — Код severity syslog (0-7) из `zh_syslog_severity_code_t`
|
|
||||||
- `hostname` — Указатель на имя устройства (только алфавитно-цифровые символы, без пробелов). Не должен быть NULL
|
|
||||||
- `app_name` — Указатель на имя приложения (только алфавитно-цифровые символы, без пробелов). Не должен быть NULL
|
|
||||||
- `message` — Указатель на строку содержимого сообщения. Не должен быть NULL
|
|
||||||
|
|
||||||
**Возвращает:**
|
|
||||||
|
|
||||||
- `ESP_OK` — Успех
|
|
||||||
- `ESP_ERR_INVALID_ARG` — hostname, app_name или message равен NULL
|
|
||||||
- `ESP_ERR_INVALID_STATE` — Клиент не инициализирован
|
|
||||||
- `ESP_ERR_NO_MEM` — Ошибка выделения памяти (буфер 1024 байта)
|
|
||||||
- `ESP_FAIL` — Операция отправки UDP не удалась
|
|
||||||
|
|
||||||
**Пример:**
|
|
||||||
|
|
||||||
```c
|
|
||||||
zh_syslog_send(ZH_USER, ZH_INFO, "esp32_device", "my_app", "Приложение запущено");
|
|
||||||
```
|
|
||||||
|
|
||||||
**Примечание:** Эта функция не является потокобезопасной. Вызывающий должен обеспечить взаимное исключение, если несколько задач могут вызывать эту функцию одновременно. Формат сообщения соответствует RFC 5424: `<priority>1 timestamp hostname app-name procid msgid - message`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Примеры использования
|
|
||||||
|
|
||||||
### Базовый пример: Инициализация и отправка сообщений
|
|
||||||
|
|
||||||
```c
|
|
||||||
#include "zh_syslog.h"
|
|
||||||
|
|
||||||
void app_main(void)
|
|
||||||
{
|
|
||||||
esp_log_level_set("zh_syslog", ESP_LOG_ERROR);
|
|
||||||
// Инициализация конфигурации со значениями по умолчанию
|
|
||||||
zh_syslog_init_config_t config = ZH_SYSLOG_INIT_CONFIG_DEFAULT();
|
|
||||||
strcpy(config.syslog_ip, "192.168.1.100"); // IP syslog сервера
|
|
||||||
|
|
||||||
// Инициализация syslog клиента
|
|
||||||
esp_err_t ret = zh_syslog_init(&config);
|
|
||||||
if (ret != ESP_OK)
|
|
||||||
{
|
|
||||||
printf("Ошибка инициализации syslog: %s\n", esp_err_to_name(ret));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Отправка информационного сообщения
|
|
||||||
zh_syslog_send(ZH_USER, ZH_INFO, "my_device", "my_app", "Приложение запущено");
|
|
||||||
|
|
||||||
// Отправка предупреждения
|
|
||||||
zh_syslog_send(ZH_USER, ZH_WARNING, "my_device", "my_app", "Низкий заряд батареи");
|
|
||||||
|
|
||||||
// Отправка сообщения об ошибке
|
|
||||||
zh_syslog_send(ZH_KERN, ZH_ERR, "my_device", "kernel", "Ошибка чтения диска");
|
|
||||||
|
|
||||||
// Деинициализация при завершении
|
|
||||||
zh_syslog_deinit();
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Пример: Интеграция с Wi-Fi и периодическая отправка журналов
|
|
||||||
|
|
||||||
```c
|
|
||||||
#include "nvs_flash.h"
|
|
||||||
#include "esp_netif.h"
|
|
||||||
#include "esp_wifi.h"
|
|
||||||
#include "esp_event.h"
|
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "freertos/event_groups.h"
|
|
||||||
#include "zh_syslog.h"
|
|
||||||
|
|
||||||
#define WIFI_SSID "ваш_ssid"
|
|
||||||
#define WIFI_PASS "ваш_password"
|
|
||||||
#define WIFI_CONNECT_SUCCESS BIT0
|
|
||||||
|
|
||||||
static EventGroupHandle_t s_event_group;
|
|
||||||
static const int WIFI_CONNECTED_BIT = BIT0;
|
|
||||||
|
|
||||||
static void wifi_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data);
|
|
||||||
|
|
||||||
void app_main(void)
|
|
||||||
{
|
|
||||||
esp_log_level_set("zh_syslog", ESP_LOG_ERROR);
|
|
||||||
nvs_flash_init();
|
|
||||||
esp_netif_init();
|
|
||||||
esp_event_loop_create_default();
|
|
||||||
esp_netif_create_default_wifi_sta();
|
|
||||||
|
|
||||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
|
||||||
esp_wifi_init(&cfg);
|
|
||||||
|
|
||||||
wifi_config_t wifi_config = {
|
|
||||||
.sta = {
|
|
||||||
.ssid = WIFI_SSID,
|
|
||||||
.password = WIFI_PASS,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
esp_wifi_set_mode(WIFI_MODE_STA);
|
|
||||||
esp_wifi_set_config(WIFI_IF_STA, &wifi_config);
|
|
||||||
esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL, NULL);
|
|
||||||
esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &wifi_event_handler, NULL, NULL);
|
|
||||||
esp_wifi_start();
|
|
||||||
|
|
||||||
s_event_group = xEventGroupCreate();
|
|
||||||
xEventGroupWaitBits(s_event_group, WIFI_CONNECTED_BIT, pdFALSE, pdTRUE, portMAX_DELAY);
|
|
||||||
|
|
||||||
// Инициализация syslog после подключения Wi-Fi
|
|
||||||
zh_syslog_init_config_t config = ZH_SYSLOG_INIT_CONFIG_DEFAULT();
|
|
||||||
strcpy(config.syslog_ip, "192.168.1.100");
|
|
||||||
zh_syslog_init(&config);
|
|
||||||
|
|
||||||
// Периодическая отправка журнальных сообщений
|
|
||||||
for (int i = 0; i < 10; i++) {
|
|
||||||
char msg[64];
|
|
||||||
snprintf(msg, sizeof(msg), "Сердцебитие #%d", i + 1);
|
|
||||||
zh_syslog_send(ZH_USER, ZH_INFO, "esp32_sensor", "logger", msg);
|
|
||||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
|
||||||
}
|
|
||||||
|
|
||||||
zh_syslog_deinit();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void wifi_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
|
|
||||||
{
|
|
||||||
if (event_id == IP_EVENT_STA_GOT_IP)
|
|
||||||
{
|
|
||||||
xEventGroupSetBits(s_event_group, WIFI_CONNECTED_BIT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Пример: Использование кодов Facility и Severity
|
|
||||||
|
|
||||||
```c
|
|
||||||
#include "zh_syslog.h"
|
|
||||||
|
|
||||||
void app_main(void)
|
|
||||||
{
|
|
||||||
esp_log_level_set("zh_syslog", ESP_LOG_ERROR);
|
|
||||||
zh_syslog_init_config_t config = ZH_SYSLOG_INIT_CONFIG_DEFAULT();
|
|
||||||
strcpy(config.syslog_ip, "192.168.1.100");
|
|
||||||
zh_syslog_init(&config);
|
|
||||||
|
|
||||||
// Критическая ошибка ядра
|
|
||||||
zh_syslog_send(ZH_KERN, ZH_CRIT, "esp32", "kernel", "Недостаточно памяти");
|
|
||||||
|
|
||||||
// Предупреждение пользовательского приложения
|
|
||||||
zh_syslog_send(ZH_USER, ZH_WARNING, "esp32", "app", "Таймаут чтения сенсора");
|
|
||||||
|
|
||||||
// Уведомление подсистемы аутентификации
|
|
||||||
zh_syslog_send(ZH_AUTH, ZH_NOTICE, "esp32", "auth", "Пользователь успешно вошёл");
|
|
||||||
|
|
||||||
// Локальный facility для пользовательского логирования
|
|
||||||
zh_syslog_send(ZH_LOCAL0, ZH_DEBUG, "esp32", "debugger", "Состояние переменной: 0x1234");
|
|
||||||
|
|
||||||
zh_syslog_deinit();
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Технические характеристики
|
|
||||||
|
|
||||||
| Параметр | Значение |
|
|
||||||
| ---------- | ---------- |
|
|
||||||
| **Размер сообщения** | 1024 байта (фиксированный буфер) |
|
|
||||||
| **Транспортный протокол** | UDP (SOCK_DGRAM) |
|
|
||||||
| **Порт по умолчанию** | 514 |
|
|
||||||
| **Стандарт форматирования** | RFC 5424 |
|
|
||||||
| **Выделение памяти** | heap_caps_calloc (MALLOC_CAP_8BIT) |
|
|
||||||
| **Потокобезопасность** | Не потокобезопасна (ответственность вызывающего) |
|
|
||||||
| **Версия ESP-IDF** | >= 5.0 |
|
|
||||||
| **Платформа** | Серия ESP32 |
|
|
||||||
| **Язык** | C (C99) |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Коды ошибок
|
|
||||||
|
|
||||||
| Код ошибки | Описание |
|
|
||||||
| ------------ | ---------- |
|
|
||||||
| `ESP_OK` | Операция выполнена успешно |
|
|
||||||
| `ESP_ERR_INVALID_ARG` | Неверный аргумент (NULL config, NULL hostname/app_name/message) |
|
|
||||||
| `ESP_ERR_INVALID_STATE` | Клиент не инициализирован (zh_syslog_init не вызвана) |
|
|
||||||
| `ESP_ERR_NO_MEM` | Ошибка выделения памяти (не хватает памяти для буфера 1024 байта) |
|
|
||||||
| `ESP_FAIL` | Создание сокета не удалось или операция отправки UDP не удалась |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Вклад в проект
|
|
||||||
|
|
||||||
Вклад приветствуется! Чтобы внести свой вклад:
|
|
||||||
|
|
||||||
1. Сделайте форк репозитория
|
|
||||||
2. Создайте ветку функции (`git checkout -b feature/AmazingFeature`)
|
|
||||||
3. Закоммитьте ваши изменения (`git commit -m 'Add some AmazingFeature'`)
|
|
||||||
4. Отправьте в ветку (`git push origin feature/AmazingFeature`)
|
|
||||||
5. Откройте Pull Request
|
|
||||||
|
|
||||||
Пожалуйста, убедитесь, что ваш код следует существующему стилю и включает соответствующую документацию.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Лицензия
|
|
||||||
|
|
||||||
Этот проект лицензирован по лицензии Apache, версия 2.0 - см. файл [LICENSE](LICENSE) для подробной информации.
|
|
||||||
|
|
||||||
### Apache License, Version 2.0
|
|
||||||
|
|
||||||
Авторское право (c) 2026 Алексей Жолтиков
|
|
||||||
|
|
||||||
Лицензировано по лицензии Apache License, Version 2.0 (далее — "Лицензия");
|
|
||||||
вы не можете использовать этот файл, кроме случаев, предусмотренных Лицензией.
|
|
||||||
Копию Лицензии можно получить по адресу:
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Если иное не требуется действующим законодательством или не согласовано в письменном виде,
|
|
||||||
программное обеспечение, распространяемое по Лицензии, распространяется на условиях "КАК ЕСТЬ",
|
|
||||||
БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, явных или подразумеваемых, включая, но не ограничиваясь, гарантии
|
|
||||||
ТОВАРНОГО СОСТОЯНИЯ, ПРИГОДНОСТИ ДЛЯ КОНКРЕТНОЙ ЦЕЛИ И НЕНАРУШЕНИЯ ПРАВ.
|
|
||||||
Смотрите Лицензию для получения конкретных прав и ограничений.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Дополнительные заметки
|
|
||||||
|
|
||||||
- **Надёжность UDP**: Эта библиотека использует UDP, который не гарантирует доставку сообщений. Для надёжной доставки реализуйте приложение-уровень подтверждения.
|
|
||||||
- **Производительность**: O(n) для форматирования сообщения (n = длина сообщения). Операция отправки блокирующая.
|
|
||||||
- **Лучшие практики**:
|
|
||||||
- Всегда проверяйте возвращаемые значения от zh_syslog_init() и zh_syslog_send()
|
|
||||||
- Вызывайте zh_syslog_deinit() перед выходом из приложения или выгрузкой модуля
|
|
||||||
- Используйте коды facility для категоризации источников журналов (KERN для ОС, USER для приложения, LOCAL0-7 для пользовательских)
|
|
||||||
- Держите hostname и app_name алфавитно-цифровыми (без пробелов) в соответствии с RFC 5424
|
|
||||||
- Настройте соответствующий уровень фильтрации журналов на syslog-сервере, чтобы избежать избыточного трафика
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*Сгенерировано для zh_syslog v1.0.0*
|
|
||||||
+14
-15
@@ -10,8 +10,8 @@
|
|||||||
* - Support for all standard syslog facility codes (0-23)
|
* - Support for all standard syslog facility codes (0-23)
|
||||||
* - Support for all standard syslog severity levels (0-7)
|
* - Support for all standard syslog severity levels (0-7)
|
||||||
* - RFC 5424 format message generation
|
* - RFC 5424 format message generation
|
||||||
* - Thread-safe initialization and deinitialization
|
* - Short messages are formatted into a stack buffer, longer ones fall back
|
||||||
* - MALLOC_CAP_8BIT memory allocation for DMA compatibility
|
* to a heap allocation with the exact required size
|
||||||
*
|
*
|
||||||
* @note Connection to the network must be established before calling zh_syslog_init().
|
* @note Connection to the network must be established before calling zh_syslog_init().
|
||||||
* @warning This library does not guarantee message delivery (UDP is connectionless).
|
* @warning This library does not guarantee message delivery (UDP is connectionless).
|
||||||
@@ -19,17 +19,15 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "stdio.h"
|
||||||
|
#include "string.h"
|
||||||
|
#include "stdint.h"
|
||||||
#include "stdbool.h"
|
#include "stdbool.h"
|
||||||
|
#include "esp_heap_caps.h"
|
||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "lwip/err.h"
|
|
||||||
#include "lwip/sockets.h"
|
#include "lwip/sockets.h"
|
||||||
#include "lwip/sys.h"
|
|
||||||
#include "lwip/netdb.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Default syslog client initialization configuration.
|
|
||||||
*/
|
|
||||||
#define ZH_SYSLOG_INIT_CONFIG_DEFAULT() \
|
#define ZH_SYSLOG_INIT_CONFIG_DEFAULT() \
|
||||||
{ \
|
{ \
|
||||||
.syslog_ip = "192.168.0.1", \
|
.syslog_ip = "192.168.0.1", \
|
||||||
@@ -116,14 +114,15 @@ extern "C"
|
|||||||
* Creates a UDP socket and configures connection parameters
|
* Creates a UDP socket and configures connection parameters
|
||||||
* for the remote syslog server.
|
* for the remote syslog server.
|
||||||
*
|
*
|
||||||
* @param[in] config Pointer to syslog client initialization configuration structure. Can point to a temporary variable
|
* @param[in] config Pointer to syslog client initialization configuration structure (must not be NULL)
|
||||||
*
|
*
|
||||||
* @return ESP_OK on success
|
* @return ESP_OK on success
|
||||||
* @return ESP_ERR_INVALID_ARG if config is NULL
|
* @return ESP_ERR_INVALID_ARG if any parameter is NULL, port is out of range, or IP is malformed
|
||||||
|
* @return ESP_ERR_INVALID_STATE if client is already initialized
|
||||||
* @return ESP_FAIL if socket creation fails
|
* @return ESP_FAIL if socket creation fails
|
||||||
*
|
*
|
||||||
* @note Connection to the network must be established before calling this function.
|
* @note Connection to the network must be established before calling this function.
|
||||||
* @note Before initialize the syslog client recommend initialize zh_syslog_init_config_t structure with default values.
|
* @note Before initializing the syslog client, it is recommended to initialize the zh_syslog_init_config_t structure with default values.
|
||||||
*/
|
*/
|
||||||
esp_err_t zh_syslog_init(const zh_syslog_init_config_t *config);
|
esp_err_t zh_syslog_init(const zh_syslog_init_config_t *config);
|
||||||
|
|
||||||
@@ -147,12 +146,12 @@ extern "C"
|
|||||||
*
|
*
|
||||||
* @param[in] facility Syslog facility code (0-23)
|
* @param[in] facility Syslog facility code (0-23)
|
||||||
* @param[in] severity Syslog severity code (0-7)
|
* @param[in] severity Syslog severity code (0-7)
|
||||||
* @param[in] hostname Pointer to device hostname that generated the message. Only alphanumeric characters without spaces
|
* @param[in] hostname Pointer to device hostname that generated the message (must not be NULL)
|
||||||
* @param[in] app_name Pointer to application name that generated the message. Only alphanumeric characters without spaces
|
* @param[in] app_name Pointer to application name that generated the message (must not be NULL)
|
||||||
* @param[in] message Pointer to the message payload to send
|
* @param[in] message Pointer to the message payload to send (must not be NULL)
|
||||||
*
|
*
|
||||||
* @return ESP_OK on success
|
* @return ESP_OK on success
|
||||||
* @return ESP_ERR_INVALID_ARG if hostname, app_name, or message is NULL
|
* @return ESP_ERR_INVALID_ARG if hostname, app_name, or message is NULL, or facility/severity is out of range
|
||||||
* @return ESP_ERR_INVALID_STATE if zh_syslog_init() was not called previously
|
* @return ESP_ERR_INVALID_STATE if zh_syslog_init() was not called previously
|
||||||
* @return ESP_ERR_NO_MEM if memory allocation fails
|
* @return ESP_ERR_NO_MEM if memory allocation fails
|
||||||
* @return ESP_FAIL if UDP send operation fails
|
* @return ESP_FAIL if UDP send operation fails
|
||||||
|
|||||||
+214
@@ -0,0 +1,214 @@
|
|||||||
|
# Описание компонента zh_syslog
|
||||||
|
|
||||||
|
## Общие сведения
|
||||||
|
|
||||||
|
**zh_syslog** — это лёгкий UDP-клиент syslog для ESP-IDF, отправляющий сообщения на удалённый syslog-сервер в формате [RFC 5424](https://datatracker.ietf.org/doc/html/rfc5424).
|
||||||
|
|
||||||
|
Компонент оборачивает стандартный BSD-сокет UDP и предоставляет несколько функций для инициализации, отправки сообщений и освобождения ресурсов.
|
||||||
|
|
||||||
|
## Основные возможности
|
||||||
|
|
||||||
|
1. **Все коды facility (0–23)** — поддержка стандартных значений по RFC 5424, включая `LOCAL0`–`LOCAL7` для локального использования.
|
||||||
|
2. **Все уровни severity (0–7)** — от `ZH_EMERG` до `ZH_DEBUG`.
|
||||||
|
3. **Формат RFC 5424** — автоматический расчёт приоритета `<PRI>` и генерация заголовка сообщения.
|
||||||
|
4. **Отправка по UDP** — сокеты не устанавливают соединения, сообщения доставляются дейтаграммами.
|
||||||
|
5. **Двухуровневая работа с памятью** — короткие сообщения форматируются в стековом буфере, длинные аллоцируются в куче точным размером.
|
||||||
|
6. **Проверка входных аргументов** — валидация IP-адреса, порта и диапазона кодов на этапе вызова.
|
||||||
|
7. **Потокобезопасные `init`/`deinit`** — защита состояния флагом инициализации (см. раздел «Ограничения» для `send`).
|
||||||
|
|
||||||
|
## Внутреннее устройство
|
||||||
|
|
||||||
|
### Структура `zh_syslog_init_config_t`
|
||||||
|
|
||||||
|
Публичная конфигурационная структура, передаваемая в `zh_syslog_init()`.
|
||||||
|
|
||||||
|
| Поле | Тип | Описание |
|
||||||
|
|------|-----|----------|
|
||||||
|
| `syslog_ip` | `char[16]` | IPv4-адрес syslog-сервера в виде строки (макс. 15 символов + `'\0'`) |
|
||||||
|
| `syslog_port` | `uint32_t` | UDP-порт сервера (диапазон 1–65535, по умолчанию 514) |
|
||||||
|
|
||||||
|
Для заполнения значений по умолчанию используется макрос `ZH_SYSLOG_INIT_CONFIG_DEFAULT()` (IP `192.168.0.1`, порт `514`).
|
||||||
|
|
||||||
|
### Внутренние переменные модуля
|
||||||
|
|
||||||
|
Не входят в публичный API и хранятся как `static` в `zh_syslog.c`.
|
||||||
|
|
||||||
|
| Переменная | Тип | Описание |
|
||||||
|
|------------|-----|----------|
|
||||||
|
| `_syslog_server` | `struct sockaddr_in` | Адрес сервера: IPv4, порт в сетевом порядке, семья `AF_INET` |
|
||||||
|
| `_socket` | `volatile int` | Дескриптор UDP-сокета, `-1` когда клиент не инициализирован |
|
||||||
|
| `_is_initialized` | `volatile bool` | Флаг состояния: `true` после успешного `init` |
|
||||||
|
|
||||||
|
Флаг `_is_initialized` используется как простой сторож состояния: `init` отказывает при уже инициализированном клиенте, `deinit` и `send` отказывают при неинициализированном.
|
||||||
|
|
||||||
|
### Управление памятью
|
||||||
|
|
||||||
|
- Короткое сообщение (помещающееся в стековый буфер `char stack_buf[256]`) форматируется прямо в стеке — аллокации в куче не происходит.
|
||||||
|
- Если `snprintf` вернул `len >= 256` (строка обрезана), память выделяется в куче ровно под `len + 1` байт через `heap_caps_calloc(..., MALLOC_CAP_8BIT)`.
|
||||||
|
- Флаг `heap_allocated` отслеживает, нужно ли освобождать буфер: `heap_caps_free()` вызывается владением только для кучного буфера — и при успехе, и при ошибке форматирования.
|
||||||
|
|
||||||
|
## API (интерфейс)
|
||||||
|
|
||||||
|
### Инициализация и освобождение
|
||||||
|
|
||||||
|
| Функция | Описание |
|
||||||
|
|---------|----------|
|
||||||
|
| `zh_syslog_init()` | Создаёт UDP-сокет и настраивает параметры соединения с сервером. |
|
||||||
|
| `zh_syslog_deinit()` | Закрывает сокет и сбрасывает состояние клиента. |
|
||||||
|
|
||||||
|
### Отправка сообщений
|
||||||
|
|
||||||
|
| Функция | Описание |
|
||||||
|
|---------|----------|
|
||||||
|
| `zh_syslog_send()` | Форматирует сообщение по RFC 5424 и отправляет его на настроенный сервер. |
|
||||||
|
|
||||||
|
### Типы и значения
|
||||||
|
|
||||||
|
| Элемент | Описание |
|
||||||
|
|---------|----------|
|
||||||
|
| `zh_syslog_facility_code_t` | Перечисление кодов facility `ZH_KERN`…`ZH_LOCAL7` (0–23). |
|
||||||
|
| `zh_syslog_severity_code_t` | Перечисление уровней severity `ZH_EMERG`…`ZH_DEBUG` (0–7). |
|
||||||
|
| `zh_syslog_init_config_t` | Структура конфигурации (IP и порт сервера). |
|
||||||
|
| `ZH_SYSLOG_INIT_CONFIG_DEFAULT()` | Макрос значений конфигурации по умолчанию. |
|
||||||
|
|
||||||
|
## Потокобезопасность
|
||||||
|
|
||||||
|
1. **Флаг состояния `_is_initialized`** — `volatile bool`, используется как сторож в `init`/`deinit`/`send` для защиты от повторной инициализации и от работы без инициализации.
|
||||||
|
2. **Дескриптор сокета `_socket`** — `volatile int`, обновляется при `init`/`deinit`.
|
||||||
|
|
||||||
|
Мьютексы и критические секции не используются. Проверка флага и последующая работа с сокетом не образуют атомарной операции, поэтому `zh_syslog_send()` **не является потокобезопасной** — подробности в разделе «Ограничения».
|
||||||
|
|
||||||
|
## Алгоритмы
|
||||||
|
|
||||||
|
### Расчёт приоритета
|
||||||
|
|
||||||
|
- Приоритет `<PRI>` считается по формуле RFC 5424: `pri = facility * 8 + severity`.
|
||||||
|
- Значение подставляется в начало сообщения в угловых скобках: `<%d>1 - ...`.
|
||||||
|
|
||||||
|
### Формат сообщения
|
||||||
|
|
||||||
|
Шаблон генерируемого сообщения:
|
||||||
|
|
||||||
|
```
|
||||||
|
<PRI>1 - HOSTNAME APP-NAME - - - MESSAGE
|
||||||
|
```
|
||||||
|
|
||||||
|
Поля `PROCID`, `MSGID` и `STRUCTURED-DATA` не заполняются и заменяются на `-` согласно RFC 5424.
|
||||||
|
|
||||||
|
### Выбор буфера под размер сообщения
|
||||||
|
|
||||||
|
- Сообщение форматируется в стековый буфер `stack_buf[256]` через `snprintf`, который возвращает полную длину строки.
|
||||||
|
- Если возвращённая длина меньше размера буфера — сокету передаётся стековый буфер.
|
||||||
|
- Если длина `>= 256` — выделяется кучный буфер точного размера `len + 1`, сообщение форматируется повторно и отправляется, после чего буфер освобождается.
|
||||||
|
|
||||||
|
## Примеры использования
|
||||||
|
|
||||||
|
### Базовый пример
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include "zh_syslog.h"
|
||||||
|
|
||||||
|
void app_main(void)
|
||||||
|
{
|
||||||
|
// Сеть (Wi-Fi/Ethernet) должна быть поднята до init
|
||||||
|
zh_syslog_init_config_t config = ZH_SYSLOG_INIT_CONFIG_DEFAULT();
|
||||||
|
strcpy(config.syslog_ip, "192.168.1.100");
|
||||||
|
config.syslog_port = 514;
|
||||||
|
|
||||||
|
if (zh_syslog_init(&config) == ESP_OK)
|
||||||
|
{
|
||||||
|
// Отправка сообщения с приоритетом USER/INFO
|
||||||
|
zh_syslog_send(ZH_USER, ZH_INFO, "esp32_node", "my_app", "Hello syslog");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Освобождение ресурсов
|
||||||
|
zh_syslog_deinit();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Работа с разными уровнями и facility
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include "zh_syslog.h"
|
||||||
|
|
||||||
|
void log_events(void)
|
||||||
|
{
|
||||||
|
zh_syslog_init_config_t config = ZH_SYSLOG_INIT_CONFIG_DEFAULT();
|
||||||
|
strcpy(config.syslog_ip, "10.0.0.5");
|
||||||
|
zh_syslog_init(&config);
|
||||||
|
|
||||||
|
// Разные facility и severity для разных событий
|
||||||
|
zh_syslog_send(ZH_KERN, ZH_ERR, "dev1", "fw", "kernel error");
|
||||||
|
zh_syslog_send(ZH_LOCAL0, ZH_WARNING, "dev1", "fw", "sensor timeout");
|
||||||
|
zh_syslog_send(ZH_DAEMON, ZH_DEBUG, "dev1", "fw", "loop tick");
|
||||||
|
|
||||||
|
zh_syslog_deinit();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Отправка длинного сообщения
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include "zh_syslog.h"
|
||||||
|
|
||||||
|
void send_long_message(void)
|
||||||
|
{
|
||||||
|
zh_syslog_init_config_t config = ZH_SYSLOG_INIT_CONFIG_DEFAULT();
|
||||||
|
strcpy(config.syslog_ip, "10.0.0.5");
|
||||||
|
zh_syslog_init(&config);
|
||||||
|
|
||||||
|
// Сообщение длиннее стекового буфера уходит через кучу
|
||||||
|
char big[512];
|
||||||
|
memset(big, 'A', sizeof(big) - 1);
|
||||||
|
big[sizeof(big) - 1] = '\0';
|
||||||
|
zh_syslog_send(ZH_USER, ZH_INFO, "dev1", "app", big);
|
||||||
|
|
||||||
|
zh_syslog_deinit();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Логирование
|
||||||
|
|
||||||
|
Компонент использует ESP-IDF логирование с тегом `"zh_syslog"`.
|
||||||
|
|
||||||
|
```c
|
||||||
|
esp_log_level_set("zh_syslog", ESP_LOG_ERROR);
|
||||||
|
```
|
||||||
|
|
||||||
|
Ошибки логируются с указанием файла, строки и имени кода ошибки (`esp_err_to_name`).
|
||||||
|
|
||||||
|
## Ошибки
|
||||||
|
|
||||||
|
| Код | Описание |
|
||||||
|
|-----|----------|
|
||||||
|
| `ESP_OK` | Успех |
|
||||||
|
| `ESP_ERR_INVALID_ARG` | Неверный аргумент: `NULL`-указатель, порт вне диапазона, некорректный IP или код вне диапазона |
|
||||||
|
| `ESP_ERR_INVALID_STATE` | Клиент уже инициализирован (`init`) либо ещё не инициализирован (`deinit`/`send`) |
|
||||||
|
| `ESP_ERR_NO_MEM` | Не удалось выделить память под длинное сообщение |
|
||||||
|
| `ESP_FAIL` | Ошибка создания сокета, форматирования или отправки UDP |
|
||||||
|
|
||||||
|
## Ограничения
|
||||||
|
|
||||||
|
1. **`zh_syslog_send()` не потокобезопасна** — проверка флага и работа с сокетом не атомарны; при конкурентном вызове из нескольких задач нужна внешняя синхронизация.
|
||||||
|
2. **Только IPv4** — адрес сервера задаётся строкой и разбирается через `inet_pton(AF_INET, ...)`, IPv6 не поддерживается.
|
||||||
|
3. **Без гарантии доставки** — UDP не подтверждает доставку, потерю сообщений компонент не отслеживает.
|
||||||
|
4. **Длина IP ограничена 15 символами** — поле `syslog_ip[16]` вмещает только IPv4-строку.
|
||||||
|
5. **Требуется активная сеть** — вызывать `zh_syslog_init()` можно только после установления сетевого соединения.
|
||||||
|
6. **Стек 256 байт на сообщение** — сообщения длиннее буфера приводят к аллокации в куче на каждую отправку.
|
||||||
|
|
||||||
|
## Требования для сборки
|
||||||
|
|
||||||
|
- ESP-IDF версии 5.0 и выше.
|
||||||
|
- FreeRTOS (входит в состав ESP-IDF).
|
||||||
|
- lwIP (стек сокетов, входит в состав ESP-IDF).
|
||||||
|
|
||||||
|
## Установка
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ваш_проект/components
|
||||||
|
git clone https://github.com/aZholtikov/zh_syslog
|
||||||
|
```
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include "zh_syslog.h"
|
||||||
|
```
|
||||||
+35
-17
@@ -1,5 +1,7 @@
|
|||||||
#include "zh_syslog.h"
|
#include "zh_syslog.h"
|
||||||
|
|
||||||
|
static const char *TAG = "zh_syslog";
|
||||||
|
|
||||||
#define ZH_LOGI(msg, ...) ESP_LOGI(TAG, msg, ##__VA_ARGS__)
|
#define ZH_LOGI(msg, ...) ESP_LOGI(TAG, msg, ##__VA_ARGS__)
|
||||||
#define ZH_LOGE(msg, err, ...) ESP_LOGE(TAG, "[%s:%d:%s] " msg, __FILE__, __LINE__, esp_err_to_name(err), ##__VA_ARGS__)
|
#define ZH_LOGE(msg, err, ...) ESP_LOGE(TAG, "[%s:%d:%s] " msg, __FILE__, __LINE__, esp_err_to_name(err), ##__VA_ARGS__)
|
||||||
|
|
||||||
@@ -11,21 +13,22 @@
|
|||||||
return err; \
|
return err; \
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *TAG = "zh_syslog";
|
static struct sockaddr_in _syslog_server = {0};
|
||||||
|
volatile static int _socket = -1;
|
||||||
static zh_syslog_init_config_t _init_config = {0}; /*!< Syslog client initialization configuration (internal copy) */
|
volatile static bool _is_initialized = false;
|
||||||
static struct sockaddr_in _syslog_server = {0}; /*!< Pre-configured syslog server address */
|
|
||||||
volatile static int _socket = 0; /*!< UDP socket file descriptor */
|
|
||||||
volatile static bool _is_initialized = false; /*!< Initialization status flag */
|
|
||||||
|
|
||||||
esp_err_t zh_syslog_init(const zh_syslog_init_config_t *config)
|
esp_err_t zh_syslog_init(const zh_syslog_init_config_t *config)
|
||||||
{
|
{
|
||||||
ESP_LOGI(TAG, "Syslog client initialization begin.");
|
ESP_LOGI(TAG, "Syslog client initialization begin.");
|
||||||
ZH_ERROR_CHECK(config != NULL, ESP_ERR_INVALID_ARG, NULL, "Syslog client initialization fail. Invalid argument.");
|
ZH_ERROR_CHECK(config != NULL, ESP_ERR_INVALID_ARG, NULL, "Syslog client initialization fail. Invalid argument.");
|
||||||
_init_config = *config;
|
ZH_ERROR_CHECK(_is_initialized == false, ESP_ERR_INVALID_STATE, NULL, "Syslog client initialization fail. Syslog client already initialized.");
|
||||||
_syslog_server.sin_addr.s_addr = inet_addr(_init_config.syslog_ip);
|
ZH_ERROR_CHECK(config->syslog_port != 0 && config->syslog_port <= 65535, ESP_ERR_INVALID_ARG, NULL, "Syslog client initialization fail. Invalid argument.");
|
||||||
|
ZH_ERROR_CHECK(memchr(config->syslog_ip, '\0', sizeof(config->syslog_ip)) != NULL, ESP_ERR_INVALID_ARG, NULL, "Syslog client initialization fail. Invalid IP.");
|
||||||
|
struct in_addr addr;
|
||||||
|
ZH_ERROR_CHECK(inet_pton(AF_INET, config->syslog_ip, &addr) == 1, ESP_ERR_INVALID_ARG, NULL, "Syslog client initialization fail. Invalid argument.");
|
||||||
|
_syslog_server.sin_addr = addr;
|
||||||
_syslog_server.sin_family = AF_INET;
|
_syslog_server.sin_family = AF_INET;
|
||||||
_syslog_server.sin_port = htons(_init_config.syslog_port);
|
_syslog_server.sin_port = htons((uint16_t)config->syslog_port);
|
||||||
_socket = socket(AF_INET, SOCK_DGRAM, 0);
|
_socket = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
ZH_ERROR_CHECK(_socket >= 0, ESP_FAIL, NULL, "Syslog client initialization fail. Create socket error.");
|
ZH_ERROR_CHECK(_socket >= 0, ESP_FAIL, NULL, "Syslog client initialization fail. Create socket error.");
|
||||||
_is_initialized = true;
|
_is_initialized = true;
|
||||||
@@ -37,24 +40,39 @@ esp_err_t zh_syslog_deinit(void)
|
|||||||
{
|
{
|
||||||
ESP_LOGI(TAG, "Syslog client deinitialization begin.");
|
ESP_LOGI(TAG, "Syslog client deinitialization begin.");
|
||||||
ZH_ERROR_CHECK(_is_initialized == true, ESP_ERR_INVALID_STATE, NULL, "Syslog client deinitialization fail. Syslog client not initialized.");
|
ZH_ERROR_CHECK(_is_initialized == true, ESP_ERR_INVALID_STATE, NULL, "Syslog client deinitialization fail. Syslog client not initialized.");
|
||||||
shutdown(_socket, 0);
|
|
||||||
close(_socket);
|
close(_socket);
|
||||||
|
_socket = -1;
|
||||||
_is_initialized = false;
|
_is_initialized = false;
|
||||||
ESP_LOGI(TAG, "Syslog client deinitialization success.");
|
ESP_LOGI(TAG, "Syslog client deinitialization success.");
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t zh_syslog_send(const zh_syslog_facility_code_t facility, const zh_syslog_severity_code_t severity, const char *hostname, const char *app_name, const char *message) // -V2008
|
esp_err_t zh_syslog_send(const zh_syslog_facility_code_t facility, const zh_syslog_severity_code_t severity, const char *hostname, const char *app_name, const char *message)
|
||||||
{
|
{
|
||||||
ESP_LOGI(TAG, "Syslog client send begin.");
|
ESP_LOGI(TAG, "Syslog client send begin.");
|
||||||
ZH_ERROR_CHECK(hostname != NULL && app_name != NULL && message != NULL, ESP_ERR_INVALID_ARG, NULL, "Syslog client send fail. Invalid argument.");
|
ZH_ERROR_CHECK(hostname != NULL && app_name != NULL && message != NULL, ESP_ERR_INVALID_ARG, NULL, "Syslog client send fail. Invalid argument.");
|
||||||
ZH_ERROR_CHECK(_is_initialized == true, ESP_ERR_INVALID_STATE, NULL, "Syslog client send fail. Syslog client not initialized.");
|
ZH_ERROR_CHECK(_is_initialized == true, ESP_ERR_INVALID_STATE, NULL, "Syslog client send fail. Syslog client not initialized.");
|
||||||
char *payload = heap_caps_calloc(1, 1024, MALLOC_CAP_8BIT);
|
ZH_ERROR_CHECK(facility >= ZH_KERN && facility <= ZH_LOCAL7 && severity >= ZH_EMERG && severity <= ZH_DEBUG, ESP_ERR_INVALID_ARG, NULL, "Syslog client send fail. Invalid argument.");
|
||||||
ZH_ERROR_CHECK(payload != NULL, ESP_ERR_NO_MEM, NULL, "Syslog client send fail. Memory allocation fail or no free memory in the heap.");
|
const int pri = ((uint8_t)facility * 8) + (uint8_t)severity;
|
||||||
sprintf(payload, "<%d>1 - %s %s - - - %s", ((uint8_t)facility * 8) + (uint8_t)severity, hostname, app_name, message);
|
char stack_buf[256];
|
||||||
int temp = sendto(_socket, payload, strlen(payload), 0, (struct sockaddr *)&_syslog_server, sizeof(_syslog_server)); // -V641
|
int len = snprintf(stack_buf, sizeof(stack_buf), "<%d>1 - %s %s - - - %s", pri, hostname, app_name, message);
|
||||||
ZH_ERROR_CHECK(temp >= 0, ESP_FAIL, heap_caps_free(payload), "Syslog client send fail. Socker error.");
|
ZH_ERROR_CHECK(len >= 0, ESP_FAIL, NULL, "Syslog client send fail. Format error.");
|
||||||
heap_caps_free(payload);
|
char *payload = stack_buf;
|
||||||
|
bool heap_allocated = false;
|
||||||
|
if (len >= sizeof(stack_buf))
|
||||||
|
{
|
||||||
|
payload = heap_caps_calloc(1, len + 1, MALLOC_CAP_8BIT);
|
||||||
|
ZH_ERROR_CHECK(payload != NULL, ESP_ERR_NO_MEM, NULL, "Syslog client send fail. Memory allocation fail or no free memory in the heap.");
|
||||||
|
int written = snprintf(payload, len + 1, "<%d>1 - %s %s - - - %s", pri, hostname, app_name, message);
|
||||||
|
ZH_ERROR_CHECK(written == len, ESP_FAIL, heap_caps_free(payload), "Syslog client send fail. Format error.");
|
||||||
|
heap_allocated = true;
|
||||||
|
}
|
||||||
|
int sent = sendto(_socket, payload, len, 0, (struct sockaddr *)&_syslog_server, sizeof(_syslog_server));
|
||||||
|
if (heap_allocated == true)
|
||||||
|
{
|
||||||
|
heap_caps_free(payload);
|
||||||
|
}
|
||||||
|
ZH_ERROR_CHECK(sent == len, ESP_FAIL, NULL, "Syslog client send fail. Socket error.");
|
||||||
ESP_LOGI(TAG, "Syslog client send success.");
|
ESP_LOGI(TAG, "Syslog client send success.");
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user