Compare commits

...
10 Commits
Author SHA1 Message Date
aZholtikov d3d3817ae2 doc: added wiki 2026-10-17 19:42:23 +03:00
aZholtikov cb65332eb4 doc: updated readme 2026-10-17 19:42:00 +03:00
aZholtikov 9defb88edd style: updated tag 2026-10-04 22:15:34 +03:00
aZholtikov 15a9db7342 perf: updated error checks 2026-10-04 13:00:19 +03:00
aZholtikov a39d9d40cf style: updated comments 2026-09-27 11:44:49 +03:00
aZholtikov dc7cf99926 doc: updated readme 2026-08-30 17:01:18 +03:00
aZholtikov 6f636f88ed doc: updated comments 2026-08-16 08:56:53 +03:00
aZholtikov 93e54ce764 doc: updated readme 2026-08-16 08:47:42 +03:00
aZholtikov da076a19e6 doc: updated wiki 2026-08-16 08:43:56 +03:00
aZholtikov c6848f6876 doc: updated readme 2026-08-16 08:01:42 +03:00
6 changed files with 418 additions and 886 deletions

No files matched your search

+155 -24
View File
@@ -1,32 +1,27 @@
# 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.
# ESP32 ESP-IDF component for syslog (UDP client)
## Features
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
3. RFC 5424 format message generation with priority calculation
4. Thread-safe initialization and deinitialization
5. MALLOC_CAP_8BIT memory allocation for DMA compatibility
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.
3. RFC 5424 format message generation with priority calculation.
4. Thread-safe initialization and deinitialization.
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
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
git clone https://github.com/aZholtikov/zh_syslog.git
git clone https://github.com/aZholtikov/zh_syslog
```
In the application, add the component:
@@ -37,8 +32,144 @@ In the application, add the component:
## 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
View File
@@ -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
View File
@@ -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
View File
@@ -10,8 +10,8 @@
* - Support for all standard syslog facility codes (0-23)
* - Support for all standard syslog severity levels (0-7)
* - RFC 5424 format message generation
* - Thread-safe initialization and deinitialization
* - MALLOC_CAP_8BIT memory allocation for DMA compatibility
* - Short messages are formatted into a stack buffer, longer ones fall back
* to a heap allocation with the exact required size
*
* @note Connection to the network must be established before calling zh_syslog_init().
* @warning This library does not guarantee message delivery (UDP is connectionless).
@@ -19,17 +19,15 @@
#pragma once
#include "stdio.h"
#include "string.h"
#include "stdint.h"
#include "stdbool.h"
#include "esp_heap_caps.h"
#include "esp_err.h"
#include "esp_log.h"
#include "lwip/err.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() \
{ \
.syslog_ip = "192.168.0.1", \
@@ -116,14 +114,15 @@ extern "C"
* Creates a UDP socket and configures connection parameters
* 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_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
*
* @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);
@@ -147,12 +146,12 @@ extern "C"
*
* @param[in] facility Syslog facility code (0-23)
* @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] app_name Pointer to application name that generated the message. Only alphanumeric characters without spaces
* @param[in] message Pointer to the message payload to send
* @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 (must not be NULL)
* @param[in] message Pointer to the message payload to send (must not be NULL)
*
* @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_NO_MEM if memory allocation fails
* @return ESP_FAIL if UDP send operation fails
+214
View File
@@ -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
View File
@@ -1,5 +1,7 @@
#include "zh_syslog.h"
static const char *TAG = "zh_syslog";
#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__)
@@ -11,21 +13,22 @@
return err; \
}
static const char *TAG = "zh_syslog";
static zh_syslog_init_config_t _init_config = {0}; /*!< Syslog client initialization configuration (internal copy) */
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 */
static struct sockaddr_in _syslog_server = {0};
volatile static int _socket = -1;
volatile static bool _is_initialized = false;
esp_err_t zh_syslog_init(const zh_syslog_init_config_t *config)
{
ESP_LOGI(TAG, "Syslog client initialization begin.");
ZH_ERROR_CHECK(config != NULL, ESP_ERR_INVALID_ARG, NULL, "Syslog client initialization fail. Invalid argument.");
_init_config = *config;
_syslog_server.sin_addr.s_addr = inet_addr(_init_config.syslog_ip);
ZH_ERROR_CHECK(_is_initialized == false, ESP_ERR_INVALID_STATE, NULL, "Syslog client initialization fail. Syslog client already initialized.");
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_port = htons(_init_config.syslog_port);
_syslog_server.sin_port = htons((uint16_t)config->syslog_port);
_socket = socket(AF_INET, SOCK_DGRAM, 0);
ZH_ERROR_CHECK(_socket >= 0, ESP_FAIL, NULL, "Syslog client initialization fail. Create socket error.");
_is_initialized = true;
@@ -37,24 +40,39 @@ esp_err_t zh_syslog_deinit(void)
{
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.");
shutdown(_socket, 0);
close(_socket);
_socket = -1;
_is_initialized = false;
ESP_LOGI(TAG, "Syslog client deinitialization success.");
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.");
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.");
char *payload = heap_caps_calloc(1, 1024, 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.");
sprintf(payload, "<%d>1 - %s %s - - - %s", ((uint8_t)facility * 8) + (uint8_t)severity, hostname, app_name, message);
int temp = sendto(_socket, payload, strlen(payload), 0, (struct sockaddr *)&_syslog_server, sizeof(_syslog_server)); // -V641
ZH_ERROR_CHECK(temp >= 0, ESP_FAIL, heap_caps_free(payload), "Syslog client send fail. Socker error.");
heap_caps_free(payload);
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.");
const int pri = ((uint8_t)facility * 8) + (uint8_t)severity;
char stack_buf[256];
int len = snprintf(stack_buf, sizeof(stack_buf), "<%d>1 - %s %s - - - %s", pri, hostname, app_name, message);
ZH_ERROR_CHECK(len >= 0, ESP_FAIL, NULL, "Syslog client send fail. Format error.");
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.");
return ESP_OK;
}