mirror of https://github.com/jeelabs/esp-link.git
syslog UDP messages are send via syslog(uint8_t facility, uint8_t severity, const char tag[], const char message[], ...); the syslog function queues any msg on system heap. If heap reaches a minimum size (8kB), syslog stops queuing. As soon as Wifi connectivity is available, syslog will send out all queued messages. Queuing will be reenabled after all pending messages are sent.pull/73/head
parent
9ec3a30c87
commit
e84900dbc7
@ -0,0 +1,369 @@ |
||||
/*
|
||||
* syslog.c |
||||
* |
||||
* |
||||
* Copyright 2015 Susi's Strolch |
||||
* |
||||
* For license information see projects "License.txt" |
||||
* |
||||
*/ |
||||
|
||||
#include <esp8266.h> |
||||
#include "config.h" |
||||
#include <syslog.h> |
||||
#include <time.h> |
||||
#include "task.h" |
||||
|
||||
#define SYSLOG_DBG |
||||
#ifdef SYSLOG_DBG |
||||
#define DBG_SYSLOG(format, ...) os_printf(format, ## __VA_ARGS__) |
||||
#else |
||||
#define DBG_SYSLOG(format, ...) do { } while(0) |
||||
#endif |
||||
|
||||
LOCAL os_timer_t check_udp_timer; |
||||
LOCAL struct espconn syslog_espconn; |
||||
LOCAL int syslog_msgid = 1; |
||||
LOCAL uint8_t syslog_task = 0; |
||||
|
||||
LOCAL syslog_host_t syslogHost; |
||||
LOCAL syslog_entry_t *syslogQueue = NULL; |
||||
|
||||
static enum syslog_state syslogState = SYSLOG_NONE; |
||||
|
||||
LOCAL void ICACHE_FLASH_ATTR syslog_add_entry(char *msg); |
||||
LOCAL void ICACHE_FLASH_ATTR syslog_check_udp(void); |
||||
LOCAL void ICACHE_FLASH_ATTR syslog_udp_sent_cb(void *arg); |
||||
#ifdef SYSLOG_UDP_RECV |
||||
LOCAL void ICACHE_FLASH_ATTR syslog_udp_recv_cb(void *arg, char *pusrdata, unsigned short length); |
||||
#endif |
||||
|
||||
#define syslog_send_udp() post_usr_task(syslog_task,0) |
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : syslog_check_udp |
||||
* Description : check whether get ip addr or not |
||||
* Parameters : none |
||||
* Returns : none |
||||
*******************************************************************************/ |
||||
LOCAL void ICACHE_FLASH_ATTR |
||||
syslog_check_udp(void) |
||||
{ |
||||
struct ip_info ipconfig; |
||||
DBG_SYSLOG("syslog_check_udp: state: %d ", syslogState); |
||||
|
||||
//disarm timer first
|
||||
os_timer_disarm(&check_udp_timer); |
||||
|
||||
//get ip info of ESP8266 station
|
||||
wifi_get_ip_info(STATION_IF, &ipconfig); |
||||
if (wifi_station_get_connect_status() == STATION_GOT_IP && ipconfig.ip.addr != 0) |
||||
{ |
||||
if (syslogState == SYSLOG_WAIT) { // waiting for initialization
|
||||
DBG_SYSLOG("connected, initializing UDP socket\n"); |
||||
syslog_init(flashConfig.syslog_host); |
||||
} |
||||
} else { |
||||
DBG_SYSLOG("waiting 100ms\n"); |
||||
if ((wifi_station_get_connect_status() == STATION_WRONG_PASSWORD || |
||||
wifi_station_get_connect_status() == STATION_NO_AP_FOUND || |
||||
wifi_station_get_connect_status() == STATION_CONNECT_FAIL)) { |
||||
os_printf("*** connect failure!!! \r\n"); |
||||
} else { |
||||
//re-arm timer to check ip
|
||||
os_timer_setfn(&check_udp_timer, (os_timer_func_t *)syslog_check_udp, NULL); |
||||
os_timer_arm(&check_udp_timer, 100, 0); |
||||
} |
||||
} |
||||
} |
||||
|
||||
LOCAL void ICACHE_FLASH_ATTR |
||||
syslog_udp_send_event(os_event_t *events) { |
||||
if (syslogQueue == NULL) |
||||
syslogState = SYSLOG_READY; |
||||
else { |
||||
int res, len = os_strlen(syslogQueue->msg); |
||||
DBG_SYSLOG("syslog_udp_send: %s\n", syslogQueue->msg); |
||||
syslog_espconn.proto.udp->remote_port = syslogHost.port; // ESP8266 udp remote port
|
||||
os_memcpy(&syslog_espconn.proto.udp->remote_ip, &syslogHost.addr.addr, 4); // ESP8266 udp remote IP
|
||||
res = espconn_send(&syslog_espconn, (uint8_t *)syslogQueue->msg, len); |
||||
if (res != 0) |
||||
os_printf("syslog_udp_send: error %d\n", res); |
||||
} |
||||
} |
||||
|
||||
LOCAL void ICACHE_FLASH_ATTR |
||||
syslog_add_entry(char *msg) |
||||
{ |
||||
syslog_entry_t *se = NULL, |
||||
*q = syslogQueue; |
||||
|
||||
// ensure we have sufficient heap for the rest of the system
|
||||
if (system_get_free_heap_size() > syslogHost.min_heap_size) { |
||||
se = os_zalloc(sizeof (syslog_entry_t) + os_strlen(msg) + 1); |
||||
os_strcpy(se->msg, msg); |
||||
se->next = NULL; |
||||
|
||||
if (q == NULL) |
||||
syslogQueue = se; |
||||
else { |
||||
while (q->next != NULL) |
||||
q = q->next; |
||||
q->next = se; // append msg to syslog queue
|
||||
} |
||||
} else { |
||||
if (syslogState != SYSLOG_HALTED) { |
||||
syslogState = SYSLOG_HALTED; |
||||
os_printf("syslog_add_entry: Warning: queue filled up, halted\n"); |
||||
// add obit syslog message
|
||||
} |
||||
} |
||||
} |
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : syslog_sent_cb |
||||
* Description : udp sent successfully |
||||
* fetch next syslog package, free old message |
||||
* Parameters : arg -- Additional argument to pass to the callback function |
||||
* Returns : none |
||||
*******************************************************************************/ |
||||
LOCAL void ICACHE_FLASH_ATTR |
||||
syslog_udp_sent_cb(void *arg) |
||||
{ |
||||
struct espconn *pespconn = arg; |
||||
DBG_SYSLOG("syslog_udp_sent_cb: %p\n", pespconn); |
||||
|
||||
// datagram is delivered - free and advance queue
|
||||
syslog_entry_t *p = syslogQueue; |
||||
syslogQueue = syslogQueue -> next; |
||||
os_free(p); |
||||
|
||||
if (syslogQueue != NULL) |
||||
syslog_send_udp(); |
||||
else |
||||
syslogState = SYSLOG_READY; |
||||
} |
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : syslog_recv_cb |
||||
* Description : Processing the received udp packet |
||||
* Parameters : arg -- Additional argument to pass to the callback function |
||||
* pusrdata -- The received data (or NULL when the connection has been closed!) |
||||
* length -- The length of received data |
||||
* Returns : none |
||||
*******************************************************************************/ |
||||
#ifdef SYSLOG_UDP_RECV |
||||
LOCAL void ICACHE_FLASH_ATTR |
||||
syslog_udp_recv_cb(void *arg, char *pusrdata, unsigned short length) |
||||
{ |
||||
DBG_SYSLOG("syslog_udp_recv_cb: %p, %p, %d\n", arg, pusrdata, length); |
||||
} |
||||
#endif |
||||
|
||||
/******************************************************************************
|
||||
* |
||||
*******************************************************************************/ |
||||
|
||||
/******************************************************************************
|
||||
* |
||||
*******************************************************************************/ |
||||
LOCAL void ICACHE_FLASH_ATTR |
||||
syslog_gethostbyname_cb(const char *name, ip_addr_t *ipaddr, void *arg) |
||||
{ |
||||
struct espconn *pespconn = (struct espconn *)arg; |
||||
(void) pespconn; |
||||
if (ipaddr != NULL) { |
||||
syslogHost.addr.addr = ipaddr->addr; |
||||
syslogState = SYSLOG_SENDING; |
||||
syslog_send_udp(); |
||||
} else { |
||||
syslogState = SYSLOG_ERROR; |
||||
DBG_SYSLOG("syslog_gethostbyname_cb: state=SYSLOG_ERROR\n"); |
||||
} |
||||
} |
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : initSyslog |
||||
* Description : Initialize the syslog library |
||||
* Parameters : hostname -- the syslog server (host:port) |
||||
* host: IP-Addr | hostname |
||||
* Returns : none |
||||
*******************************************************************************/ |
||||
void ICACHE_FLASH_ATTR |
||||
syslog_init(char *syslog_server) |
||||
{ |
||||
char host[32], *port = &host[0]; |
||||
|
||||
syslog_task = register_usr_task(syslog_udp_send_event); |
||||
|
||||
syslogState = SYSLOG_WAIT; |
||||
syslogHost.min_heap_size = MINIMUM_HEAP_SIZE; |
||||
syslogHost.port = 514; |
||||
|
||||
os_strncpy(host, syslog_server, 32); |
||||
while (*port && *port != ':') // find port delimiter
|
||||
port++; |
||||
if (*port) { |
||||
*port++ = '\0'; |
||||
syslogHost.port = atoi(port); |
||||
} |
||||
|
||||
wifi_set_broadcast_if(STATIONAP_MODE); // send UDP broadcast from both station and soft-AP interface
|
||||
syslog_espconn.type = ESPCONN_UDP; |
||||
syslog_espconn.proto.udp = (esp_udp *)os_zalloc(sizeof(esp_udp)); |
||||
syslog_espconn.proto.udp->local_port = espconn_port(); // set a available port
|
||||
#ifdef SYSLOG_UDP_RECV |
||||
espconn_regist_recvcb(&syslog_espconn, syslog_udp_recv_cb); // register a udp packet receiving callback
|
||||
#endif |
||||
espconn_regist_sentcb(&syslog_espconn, syslog_udp_sent_cb); // register a udp packet sent callback
|
||||
espconn_create(&syslog_espconn); // create udp
|
||||
|
||||
if (UTILS_StrToIP((const char *)host, (void*)&syslogHost.addr)) { |
||||
syslogState = SYSLOG_SENDING; |
||||
syslog_send_udp(); |
||||
} else { |
||||
static struct espconn espconn_ghbn; |
||||
espconn_gethostbyname(&espconn_ghbn, host, &syslogHost.addr, syslog_gethostbyname_cb); |
||||
// syslog_send_udp is called by syslog_gethostbyname_cb()
|
||||
} |
||||
DBG_SYSLOG("syslog_init: host: %s, port: %d, lport: %d, recvcb: %p, sentcb: %p, state: %d\n", |
||||
host, syslogHost.port, syslog_espconn.proto.udp->local_port, |
||||
syslog_udp_recv_cb, syslog_udp_sent_cb, syslogState ); |
||||
} |
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : syslog |
||||
* Description : compose and queue a new syslog message |
||||
* Parameters : facility |
||||
* severity |
||||
* tag |
||||
* message |
||||
* ... |
||||
* |
||||
* SYSLOG-MSG = HEADER SP STRUCTURED-DATA [SP MSG] |
||||
|
||||
HEADER = PRI VERSION SP TIMESTAMP SP HOSTNAME |
||||
SP APP-NAME SP PROCID SP MSGID |
||||
PRI = "<" PRIVAL ">" |
||||
PRIVAL = 1*3DIGIT ; range 0 .. 191 |
||||
VERSION = NONZERO-DIGIT 0*2DIGIT |
||||
HOSTNAME = NILVALUE / 1*255PRINTUSASCII |
||||
|
||||
APP-NAME = NILVALUE / 1*48PRINTUSASCII |
||||
PROCID = NILVALUE / 1*128PRINTUSASCII |
||||
MSGID = NILVALUE / 1*32PRINTUSASCII |
||||
|
||||
TIMESTAMP = NILVALUE / FULL-DATE "T" FULL-TIME |
||||
FULL-DATE = DATE-FULLYEAR "-" DATE-MONTH "-" DATE-MDAY |
||||
DATE-FULLYEAR = 4DIGIT |
||||
DATE-MONTH = 2DIGIT ; 01-12 |
||||
DATE-MDAY = 2DIGIT ; 01-28, 01-29, 01-30, 01-31 based on |
||||
; month/year |
||||
FULL-TIME = PARTIAL-TIME TIME-OFFSET |
||||
PARTIAL-TIME = TIME-HOUR ":" TIME-MINUTE ":" TIME-SECOND |
||||
[TIME-SECFRAC] |
||||
TIME-HOUR = 2DIGIT ; 00-23 |
||||
TIME-MINUTE = 2DIGIT ; 00-59 |
||||
TIME-SECOND = 2DIGIT ; 00-59 |
||||
TIME-SECFRAC = "." 1*6DIGIT |
||||
TIME-OFFSET = "Z" / TIME-NUMOFFSET |
||||
TIME-NUMOFFSET = ("+" / "-") TIME-HOUR ":" TIME-MINUTE |
||||
|
||||
|
||||
STRUCTURED-DATA = NILVALUE / 1*SD-ELEMENT |
||||
SD-ELEMENT = "[" SD-ID *(SP SD-PARAM) "]" |
||||
SD-PARAM = PARAM-NAME "=" %d34 PARAM-VALUE %d34 |
||||
SD-ID = SD-NAME |
||||
PARAM-NAME = SD-NAME |
||||
PARAM-VALUE = UTF-8-STRING ; characters '"', '\' and |
||||
; ']' MUST be escaped. |
||||
SD-NAME = 1*32PRINTUSASCII |
||||
; except '=', SP, ']', %d34 (") |
||||
|
||||
MSG = MSG-ANY / MSG-UTF8 |
||||
MSG-ANY = *OCTET ; not starting with BOM |
||||
MSG-UTF8 = BOM UTF-8-STRING |
||||
BOM = %xEF.BB.BF |
||||
UTF-8-STRING = *OCTET ; UTF-8 string as specified |
||||
; in RFC 3629 |
||||
|
||||
OCTET = %d00-255 |
||||
SP = %d32 |
||||
PRINTUSASCII = %d33-126 |
||||
NONZERO-DIGIT = %d49-57 |
||||
DIGIT = %d48 / NONZERO-DIGIT |
||||
NILVALUE = "-" |
||||
* |
||||
* TIMESTAMP: realtime_clock == 0 ? timertick / 10⁶ : realtime_clock |
||||
* HOSTNAME hostname |
||||
* APPNAME: ems-esp-link |
||||
* PROCID: timertick |
||||
* MSGID: NILVALUE |
||||
* |
||||
* Returns : none |
||||
*******************************************************************************/ |
||||
void ICACHE_FLASH_ATTR |
||||
syslog(uint8_t facility, uint8_t severity, const char *tag, const char *fmt, ...) |
||||
{ |
||||
char udp_payload[1024], |
||||
*p = udp_payload; |
||||
uint32_t tick = WDEV_NOW(); // 0 ... 4294.967295s
|
||||
|
||||
DBG_SYSLOG("syslog: state=%d ", syslogState); |
||||
if (syslogState == SYSLOG_ERROR || |
||||
syslogState == SYSLOG_HALTED) |
||||
return; |
||||
|
||||
// The Priority value is calculated by first multiplying the Facility
|
||||
// number by 8 and then adding the numerical value of the Severity.
|
||||
int sl = os_sprintf(p, "<%d> ", facility * 8 + severity); |
||||
p += sl; |
||||
|
||||
// strftime doesn't work as expected - or adds 8k overhead.
|
||||
// so let's do poor man conversion - format is fixed anyway
|
||||
if (flashConfig.syslog_showdate == 0) |
||||
sl = os_sprintf(p, "- "); |
||||
else { |
||||
time_t now = NULL; |
||||
struct tm *tp = NULL; |
||||
|
||||
// create timestamp: FULL-DATE "T" PARTIAL-TIME "Z": 'YYYY-mm-ddTHH:MM:SSZ '
|
||||
// as long as realtime_stamp is 0 we use tick div 10⁶ as date
|
||||
now = (realtime_stamp == 0) ? (tick / 1000000) : realtime_stamp; |
||||
tp = gmtime(&now); |
||||
|
||||
sl = os_sprintf(p, "%4d-%02d-%02dT%02d:%02d:%02dZ ", |
||||
tp->tm_year + 1900, tp->tm_mon + 1, tp->tm_mday, |
||||
tp->tm_hour, tp->tm_min, tp->tm_sec); |
||||
} |
||||
p += sl; |
||||
|
||||
// add HOSTNAME APP-NAME PROCID MSGID
|
||||
if (flashConfig.syslog_showtick) |
||||
sl = os_sprintf(p, "%s %s %lu.%06lu %d ", flashConfig.hostname, tag, tick / 1000000, tick % 1000000, syslog_msgid++); |
||||
else |
||||
sl = os_sprintf(p, "%s %s - %d ", flashConfig.hostname, tag, syslog_msgid++); |
||||
p += sl; |
||||
|
||||
// append syslog message
|
||||
va_list arglist; |
||||
va_start(arglist, fmt); |
||||
sl = ets_vsprintf(p, fmt, arglist ); |
||||
va_end(arglist); |
||||
|
||||
DBG_SYSLOG("msg: %s\n", udp_payload); |
||||
syslog_add_entry(udp_payload); // add to message queue
|
||||
|
||||
if (syslogState == SYSLOG_READY) { |
||||
syslogState = SYSLOG_SENDING; |
||||
syslog_send_udp(); |
||||
} |
||||
|
||||
if (syslogState == SYSLOG_NONE) { |
||||
//set a timer to check whether we got ip from router succeed or not.
|
||||
os_timer_disarm(&check_udp_timer); |
||||
os_timer_setfn(&check_udp_timer, (os_timer_func_t *)syslog_check_udp, NULL); |
||||
os_timer_arm(&check_udp_timer, 100, 0); |
||||
syslogState = SYSLOG_WAIT; |
||||
} |
||||
} |
@ -0,0 +1,93 @@ |
||||
/*
|
||||
* syslog.h |
||||
* |
||||
* |
||||
* Copyright 2015 Susi's Strolch |
||||
* |
||||
* For license information see projects "License.txt" |
||||
* |
||||
* part of syslog.c - client library |
||||
* |
||||
*/ |
||||
|
||||
|
||||
#ifndef _SYSLOG_H |
||||
#define _SYSLOG_H |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
enum syslog_state { |
||||
SYSLOG_NONE, // not initialized
|
||||
SYSLOG_WAIT, // initialized, waiting for Wifi
|
||||
SYSLOG_READY, // Wifi established, ready to send
|
||||
SYSLOG_SENDING, // UDP package on the air
|
||||
SYSLOG_HALTED, // heap full, discard message
|
||||
SYSLOG_ERROR, |
||||
}; |
||||
|
||||
enum syslog_priority { |
||||
SYSLOG_PRIO_EMERG, /* system is unusable */ |
||||
SYSLOG_PRIO_ALERT, /* action must be taken immediately */ |
||||
SYSLOG_PRIO_CRIT, /* critical conditions */ |
||||
SYSLOG_PRIO_ERR, /* error conditions */ |
||||
SYSLOG_PRIO_WARNING, /* warning conditions */ |
||||
SYSLOG_PRIO_NOTICE, /* normal but significant condition */ |
||||
SYSLOG_PRIO_INFO, /* informational */ |
||||
SYSLOG_PRIO_DEBUG, /* debug-level messages */ |
||||
}; |
||||
|
||||
enum syslog_facility { |
||||
SYSLOG_FAC_KERN, /* kernel messages */ |
||||
SYSLOG_FAC_USER, /* random user-level messages */ |
||||
SYSLOG_FAC_MAIL, /* mail system */ |
||||
SYSLOG_FAC_DAEMON, /* system daemons */ |
||||
SYSLOG_FAC_AUTH, /* security/authorization messages */ |
||||
SYSLOG_FAC_SYSLOG, /* messages generated internally by syslogd */ |
||||
SYSLOG_FAC_LPR, /* line printer subsystem */ |
||||
SYSLOG_FAC_NEWS, /* network news subsystem */ |
||||
SYSLOG_FAC_UUCP, /* UUCP subsystem */ |
||||
SYSLOG_FAC_CRON, /* clock daemon */ |
||||
SYSLOG_FAC_AUTHPRIV,/* security/authorization messages (private) */ |
||||
SYSLOG_FAC_FTP, /* ftp daemon */ |
||||
SYSLOG_FAC_LOCAL0, /* reserved for local use */ |
||||
SYSLOG_FAC_LOCAL1, /* reserved for local use */ |
||||
SYSLOG_FAC_LOCAL2, /* reserved for local use */ |
||||
SYSLOG_FAC_LOCAL3, /* reserved for local use */ |
||||
SYSLOG_FAC_LOCAL4, /* reserved for local use */ |
||||
SYSLOG_FAC_LOCAL5, /* reserved for local use */ |
||||
SYSLOG_FAC_LOCAL6, /* reserved for local use */ |
||||
SYSLOG_FAC_LOCAL7, /* reserved for local use */ |
||||
}; |
||||
|
||||
#define MINIMUM_HEAP_SIZE 8192 |
||||
#define REG_READ(_r) (*(volatile uint32 *)(_r)) |
||||
#define WDEV_NOW() REG_READ(0x3ff20c00) |
||||
|
||||
extern uint32_t realtime_stamp; // 1sec NTP ticker
|
||||
|
||||
typedef struct syslog_host_t syslog_host_t; |
||||
struct syslog_host_t { |
||||
uint32_t min_heap_size; // minimum allowed heap size when buffering
|
||||
ip_addr_t addr; |
||||
uint16_t port; |
||||
}; |
||||
|
||||
// buffered syslog event - f.e. if network stack isn't up and running
|
||||
typedef struct syslog_entry_t syslog_entry_t; |
||||
struct syslog_entry_t { |
||||
syslog_entry_t *next; |
||||
char msg[]; |
||||
}; |
||||
|
||||
syslog_host_t syslogserver; |
||||
|
||||
void ICACHE_FLASH_ATTR syslog_init(char *syslog_server); |
||||
void ICACHE_FLASH_ATTR syslog(uint8_t facility, uint8_t severity, const char tag[], const char message[], ...); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* _SYSLOG_H */ |
Loading…
Reference in new issue