diff --git a/components/lua/modules/sys/loslib_adds.inc b/components/lua/modules/sys/loslib_adds.inc index 813610ac3..bde4243a8 100644 --- a/components/lua/modules/sys/loslib_adds.inc +++ b/components/lua/modules/sys/loslib_adds.inc @@ -567,6 +567,33 @@ static int os_setrsyslog(lua_State *L) { } #endif +#if CONFIG_LUA_RTOS_LUA_USE_MQTT +static int os_setmsyslog(lua_State *L) { + if (lua_gettop(L) > 0) { + if (lua_type(L, 1) == LUA_TNIL) { + syslog_setlogmqtt(0, NULL); + return 0; + } + const char *topic = luaL_optstring(L, 2, NULL); //order matters + luaL_checktype(L, 1, LUA_TUSERDATA); + lua_pushvalue(L, 1); + int mqtt_ref = luaL_ref(L, LUA_REGISTRYINDEX); + const int ret = syslog_setlogmqtt(mqtt_ref, topic); + if (ret) { + lua_rawgeti(L, LUA_REGISTRYINDEX, ret); + return 1; + } + return 0; + } + const int ret = syslog_getlogmqtt(); + if (ret) { + lua_rawgeti(L, LUA_REGISTRYINDEX, ret); + return 1; + } + return 0; +} +#endif + static int os_stats(lua_State *L) { const char *stat = luaL_optstring(L, 1, NULL); diff --git a/components/lua/src/loslib.c b/components/lua/src/loslib.c index 4f84fe3b3..5d41f3ea9 100644 --- a/components/lua/src/loslib.c +++ b/components/lua/src/loslib.c @@ -518,6 +518,9 @@ static const LUA_REG_TYPE syslib[] = { LSTRKEY( "syslog" ), LFUNCVAL( os_syslog ) }, #if CONFIG_LUA_RTOS_USE_RSYSLOG { LSTRKEY( "rsyslog" ), LFUNCVAL( os_setrsyslog ) }, +#endif +#if CONFIG_LUA_RTOS_LUA_USE_MQTT + { LSTRKEY( "msyslog" ), LFUNCVAL( os_setmsyslog ) }, #endif { LSTRKEY( "stats" ), LFUNCVAL( os_stats ) }, { LSTRKEY( "format" ), LFUNCVAL( os_format ) }, diff --git a/components/sys/sys/syslog.h b/components/sys/sys/syslog.h index a04625762..67b053ff4 100644 --- a/components/sys/sys/syslog.h +++ b/components/sys/sys/syslog.h @@ -173,5 +173,12 @@ void syslog(int, const char *, ...); void vsyslog(int, const char *, va_list); int getlogmask(); int getlogstat(); +#if CONFIG_LUA_RTOS_USE_RSYSLOG const char *syslog_setloghost (const char *host); const char *syslog_getloghost (); +#endif +#if CONFIG_LUA_RTOS_LUA_USE_MQTT +int syslog_setlogmqtt (const int mqtt_ref, const char *topic); +int syslog_getlogmqtt (); +#endif + diff --git a/components/sys/unix/syslog.c b/components/sys/unix/syslog.c index 16bb8373d..1f1b5ea65 100644 --- a/components/sys/unix/syslog.c +++ b/components/sys/unix/syslog.c @@ -1,6 +1,6 @@ /* * Copyright (c) 1983, 1988, 1993 - * The Regents of the University of California. All rights reserved. + * The Regents of the University of California. All rights reserved. * * Copyright (C) 2015 - 2018 * IBEROXARXA SERVICIOS INTEGRALES, S.L. @@ -23,8 +23,8 @@ * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. + * This product includes software developed by the University of + * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -91,229 +91,261 @@ static const char *logHostDefault = CONFIG_LUA_RTOS_RSYSLOG_SERVER; struct sockaddr_in logAddr; #endif static FILE *logFile = NULL; -static int logStat = 0; /* status bits, set by openlog() */ -static int logFacility = LOG_USER; /* default facility code */ -static int logMask = 0b11111111; /* mask of priorities to be logged */ +static int logStat = 0; /* status bits, set by openlog() */ +static int logFacility = LOG_USER; /* default facility code */ +static int logMask = 0b11111111; /* mask of priorities to be logged */ void vsyslog(int pri, register const char *fmt, va_list app); +#if CONFIG_LUA_RTOS_LUA_USE_MQTT +#include "lauxlib.h" +static int logMQTT = 0; +static char *logTopic = NULL; +static int msyslog_vprintf( const char *str, va_list l ); +#endif + /* * syslog, vsyslog -- - * print message on log file; output is intended for syslogd(8). + * print message on log file; output is intended for syslogd(8). */ void #if __STDC__ syslog(int pri, const char *fmt, ...) #else syslog(pri, fmt, va_alist) - int pri; - char *fmt; - va_dcl + int pri; + char *fmt; + va_dcl #endif { - if (!fmt) return; + if (!fmt) return; - va_list ap; + va_list ap; #if __STDC__ - va_start(ap, fmt); + va_start(ap, fmt); #else - va_start(ap); + va_start(ap); #endif - vsyslog(pri, fmt, ap); - va_end(ap); + vsyslog(pri, fmt, ap); + va_end(ap); } void vsyslog(pri, fmt, ap) - int pri; - register const char *fmt; - va_list ap; + int pri; + register const char *fmt; + va_list ap; { - register int cnt; - register char *p; - char *tbuf; - time_t now; - int fd; - int has_cr_lf = 0; - - #define INTERNALLOG LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID - - if (!fmt) return; - - /* Check for invalid bits. */ - if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) { - pri &= LOG_PRIMASK|LOG_FACMASK; - } - - /* Check priority against setlogmask values. */ - if (!(LOG_MASK(LOG_PRI(pri)) & logMask)) - return; - - // Allocate space - tbuf = (char *)malloc(MAX_BUFF + 3); - if (!tbuf) return; - - /* Set default facility if none specified. */ - if ((pri & LOG_FACMASK) == 0) - pri |= logFacility; - - /* Build the message. */ - - (void)time(&now); - p = tbuf + snprintf(tbuf, MAX_BUFF, "<%d>", pri); - if (logStat & LOG_PID) { - p += snprintf(p, MAX_BUFF - (p - tbuf), "[%d]", getpid()); - } - cnt = vsnprintf(p, MAX_BUFF - (p - tbuf), fmt, ap); - if (cnt > MAX_BUFF - (p - tbuf)) { - p += (MAX_BUFF - (p - tbuf)) - 1; - } - else { - p += cnt; - } - - cnt = p - tbuf; - has_cr_lf = ((tbuf[cnt-1] == '\n') && (tbuf[cnt-2] == '\r')); - - if (logStat & LOG_CONS) { - fd = fileno(_GLOBAL_REENT->_stdout); - if (!has_cr_lf) { - while(cnt && tbuf[cnt-1] == '\n') cnt--; - - (void)strcat(tbuf, "\r\n"); - cnt += 2; - has_cr_lf = 1; - } - - p = index(tbuf, '>') + 1; - (void)write(fd, p, cnt - (p - tbuf)); - } - - if (NULL != logFile) { - char *t = tbuf + strlen(tbuf); - - // Remove end \r | \n - while ((*t == '\r') || (*t == '\n')) { - *t = '\0'; - t--; - cnt--; - } - - (void)strcat(tbuf, "\n"); - cnt += 1; - p = index(tbuf, '>') + 1; - - fwrite(p, cnt - (p - tbuf), 1, logFile); - fflush(logFile); - } + register int cnt; + register char *p; + char *tbuf; + time_t now; + int fd; + int has_cr_lf = 0; + + #define INTERNALLOG LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID + + if (!fmt) return; + + /* Check for invalid bits. */ + if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) { + pri &= LOG_PRIMASK|LOG_FACMASK; + } + + /* Check priority against setlogmask values. */ + if (!(LOG_MASK(LOG_PRI(pri)) & logMask)) + return; + + // Allocate space + tbuf = (char *)malloc(MAX_BUFF + 3); + if (!tbuf) { + //emergency print (!) + fprintf(stderr, "syslog: Out of memory! Printing message to stderr\n"); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + return; + } + + /* Set default facility if none specified. */ + if ((pri & LOG_FACMASK) == 0) + pri |= logFacility; + + /* Build the message. */ + + (void)time(&now); + p = tbuf + snprintf(tbuf, MAX_BUFF, "<%d>", pri); + if (logStat & LOG_PID) { + p += snprintf(p, MAX_BUFF - (p - tbuf), "[%d]", getpid()); + } + cnt = vsnprintf(p, MAX_BUFF - (p - tbuf), fmt, ap); + if (cnt > MAX_BUFF - (p - tbuf)) { + p += (MAX_BUFF - (p - tbuf)) - 1; + } + else { + p += cnt; + } + + cnt = p - tbuf; + has_cr_lf = ((tbuf[cnt-1] == '\n') && (tbuf[cnt-2] == '\r')); + + if (logStat & LOG_CONS) { + fd = fileno(_GLOBAL_REENT->_stdout); + if (!has_cr_lf) { + while(cnt && tbuf[cnt-1] == '\n') cnt--; + + (void)strcat(tbuf, "\r\n"); + cnt += 2; + has_cr_lf = 1; + } + + p = index(tbuf, '>') + 1; + (void)write(fd, p, cnt - (p - tbuf)); + } + + if (NULL != logFile) { + char *t = tbuf + strlen(tbuf); + + // Remove end \r | \n + while ((*t == '\r') || (*t == '\n')) { + *t = '\0'; + t--; + cnt--; + } + + (void)strcat(tbuf, "\n"); + cnt += 1; + p = index(tbuf, '>') + 1; + + fwrite(p, cnt - (p - tbuf), 1, logFile); + fflush(logFile); + } #if CONFIG_LUA_RTOS_USE_RSYSLOG - if (0 != logSock) { - LOCK_TCPIP_CORE() - sendto(logSock,tbuf,cnt,0,(struct sockaddr *)&logAddr,sizeof(logAddr)); - UNLOCK_TCPIP_CORE() - } + if (0 != logSock) { + LOCK_TCPIP_CORE() + sendto(logSock,tbuf,cnt,0,(struct sockaddr *)&logAddr,sizeof(logAddr)); + UNLOCK_TCPIP_CORE() + } #endif - free(tbuf); +#if CONFIG_LUA_RTOS_LUA_USE_MQTT + if (0 != logMQTT) { + lua_State *L = pvGetLuaState(); // Get the thread's Lua state + lua_rawgeti(L, LUA_REGISTRYINDEX, logMQTT); + lua_getfield(L, -1, "publish"); + lua_rawgeti(L, LUA_REGISTRYINDEX, logMQTT); + lua_pushstring(L, logTopic ? logTopic : "syslog"); + lua_pushlstring(L, tbuf, cnt); + lua_pushinteger(L, 0); + lua_pcall(L, 4, 0, 0); + } +#endif + + free(tbuf); } #if CONFIG_LUA_RTOS_USE_RSYSLOG -static int syslog_logging_vprintf( const char *str, va_list l ) { - // Allocate space - char* tbuf = (char *)malloc(MAX_BUFF+1); - if (tbuf) { - int len = vsnprintf((char*)tbuf, MAX_BUFF, str, l); - - if (0 != logSock) { - LOCK_TCPIP_CORE() - sendto(logSock,tbuf,len,0,(struct sockaddr *)&logAddr,sizeof(logAddr)); - UNLOCK_TCPIP_CORE() - } - - free(tbuf); - } - - return vprintf( str, l ); +static int rsyslog_vprintf( const char *str, va_list l ) { + // Allocate space + char* tbuf = (char *)malloc(MAX_BUFF+1); + if (tbuf) { + int len = vsnprintf((char*)tbuf, MAX_BUFF, str, l); + + if (0 != logSock) { + LOCK_TCPIP_CORE() + sendto(logSock,tbuf,len,0,(struct sockaddr *)&logAddr,sizeof(logAddr)); + UNLOCK_TCPIP_CORE() + } + + free(tbuf); + } + + return vprintf( str, l ); } static void reconnect_syslog() { - if (0 != logSock) { - close(logSock); - } - logSock = 0; - - esp_log_set_vprintf(vprintf); - - if (NETWORK_AVAILABLE()) { - if (!logHost) logHost = (char*)logHostDefault; - if (0 == strlen(logHost) || 0 == strcmp(logHost,"0.0.0.0")) - return; //user wants to disable remote logging - - // Resolve name - const struct addrinfo hints = { - .ai_family = AF_INET, - .ai_socktype = SOCK_STREAM, - }; - - struct addrinfo *result; - int err = getaddrinfo(logHost, NULL, &hints, &result); - if (err != 0 || result == NULL) { - printf("could not resolve host %s\n", logHost); - } - else { - (void)memset((void *)&logAddr, 0x00,sizeof(logAddr)); - - if (result->ai_family == AF_INET) { - struct sockaddr_in *p = (struct sockaddr_in *)result->ai_addr; - p->sin_port = htons(CONFIG_LUA_RTOS_RSYSLOG_PORT); - memcpy(&logAddr, p, sizeof(struct sockaddr_in)); - } else if (result->ai_family == AF_INET6) { - struct sockaddr_in6 *p = (struct sockaddr_in6 *)result->ai_addr; - p->sin6_port = htons(CONFIG_LUA_RTOS_RSYSLOG_PORT); - p->sin6_family = AF_INET6; - memcpy(&logAddr, p, sizeof(struct sockaddr_in6)); - } else { - printf("Unsupported protocol family %d", result->ai_family); - } - - freeaddrinfo(result); - - if (logAddr.sin_port != 0) { - logSock = socket(AF_INET, SOCK_DGRAM, 0); - if (0 != logSock) { - fcntl(logSock, F_SETFL, O_NONBLOCK); - int reuse = 1; - setsockopt(logSock,SOL_SOCKET,SO_REUSEADDR,(void *)&reuse,sizeof(reuse)); - - esp_log_set_vprintf(syslog_logging_vprintf); - } - } - } - } + if (0 != logSock) { + close(logSock); + } + logSock = 0; + + esp_log_set_vprintf(vprintf); + + if (NETWORK_AVAILABLE()) { + if (!logHost) logHost = (char*)logHostDefault; + if (0 == strlen(logHost) || 0 == strcmp(logHost,"0.0.0.0")) + return; //user wants to disable remote logging + + // Resolve name + const struct addrinfo hints = { + .ai_family = AF_INET, + .ai_socktype = SOCK_STREAM, + }; + + struct addrinfo *result; + int err = getaddrinfo(logHost, NULL, &hints, &result); + if (err != 0 || result == NULL) { + printf("could not resolve host %s\n", logHost); + } + else { + (void)memset((void *)&logAddr, 0x00,sizeof(logAddr)); + + if (result->ai_family == AF_INET) { + struct sockaddr_in *p = (struct sockaddr_in *)result->ai_addr; + p->sin_port = htons(CONFIG_LUA_RTOS_RSYSLOG_PORT); + memcpy(&logAddr, p, sizeof(struct sockaddr_in)); + } else if (result->ai_family == AF_INET6) { + struct sockaddr_in6 *p = (struct sockaddr_in6 *)result->ai_addr; + p->sin6_port = htons(CONFIG_LUA_RTOS_RSYSLOG_PORT); + p->sin6_family = AF_INET6; + memcpy(&logAddr, p, sizeof(struct sockaddr_in6)); + } else { + printf("Unsupported protocol family %d", result->ai_family); + } + + freeaddrinfo(result); + + if (logAddr.sin_port != 0) { + logSock = socket(AF_INET, SOCK_DGRAM, 0); + if (0 != logSock) { + fcntl(logSock, F_SETFL, O_NONBLOCK); + int reuse = 1; + setsockopt(logSock,SOL_SOCKET,SO_REUSEADDR,(void *)&reuse,sizeof(reuse)); + + esp_log_set_vprintf(rsyslog_vprintf); + } + } + } + } + +#if CONFIG_LUA_RTOS_LUA_USE_MQTT + if (logMQTT) { + esp_log_set_vprintf(msyslog_vprintf); + } +#endif } static void syslog_net_callback(system_event_t *event){ - if ( (NETWORK_AVAILABLE() && (0 == logSock)) || - (!NETWORK_AVAILABLE() && (0 != logSock)) ) { - reconnect_syslog(); - } + if ( (NETWORK_AVAILABLE() && (0 == logSock)) || + (!NETWORK_AVAILABLE() && (0 != logSock)) ) { + reconnect_syslog(); + } } #endif int openlog(logstat, logfac) - int logstat, logfac; + int logstat, logfac; { - logStat = logstat; - if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0) - logFacility = logfac; + logStat = logstat; + if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0) + logFacility = logfac; - if (NULL != logFile) { - fclose(logFile); - } + if (NULL != logFile) { + fclose(logFile); + } - logFile = NULL; + logFile = NULL; char file[PATH_MAX + 1]; @@ -323,78 +355,144 @@ int openlog(logstat, logfac) logFile = fopen(file,"a+"); } - if (NULL != logFile) { - fflush(logFile); - } + if (NULL != logFile) { + fflush(logFile); + } #if CONFIG_LUA_RTOS_USE_RSYSLOG - reconnect_syslog(); + reconnect_syslog(); - driver_error_t *error; - if ((error = net_event_register_callback(syslog_net_callback))) { - printf("couldn't register net callback, please restart syslog service from lua using after changing connectivity\n"); - printf("you may use the command 'os.logcons(os.logcons())' to restart the syslog service from lua\n"); - } + driver_error_t *error; + if ((error = net_event_register_callback(syslog_net_callback))) { + printf("couldn't register net callback, please restart syslog service from lua after changing connectivity\n"); + printf("you may use the command 'os.logcons(os.logcons())' to restart the syslog service from lua\n"); + } #endif - return (logFile == NULL); + return (logFile == NULL); } void closelog() { - if (NULL != logFile) { - fclose(logFile); - } - logFile = NULL; + if (NULL != logFile) { + fclose(logFile); + } + logFile = NULL; #if CONFIG_LUA_RTOS_USE_RSYSLOG - if (0 != logSock) { - close(logSock); - } - logSock = 0; - - driver_error_t *error; - if ((error = net_event_unregister_callback(syslog_net_callback))) { - printf("couldn't unregister net callback\n"); - } + if (0 != logSock) { + close(logSock); + } + logSock = 0; + + driver_error_t *error; + if ((error = net_event_unregister_callback(syslog_net_callback))) { + printf("couldn't unregister net callback\n"); + } #endif } /* setlogmask -- set the log mask level */ int setlogmask(int pmask) { - int omask; + int omask; - omask = logMask; - if (pmask != 0) - logMask = pmask; + omask = logMask; + if (pmask != 0) + logMask = pmask; - return (omask); + return (omask); } int getlogmask() { - return logMask; + return logMask; } int getlogstat() { - return logStat; + return logStat; } #if CONFIG_LUA_RTOS_USE_RSYSLOG const char *syslog_setloghost (const char *host) { - if (logHost && logHost != logHostDefault) - free (logHost); - logHost = NULL; - if (!host) - return (NULL); + if (logHost && logHost != logHostDefault) + free (logHost); + logHost = NULL; + if (!host) + return (NULL); - logHost = strdup (host); - reconnect_syslog(); + logHost = strdup (host); + reconnect_syslog(); - return logHost; + return logHost; } const char *syslog_getloghost () { - return logHost; + return logHost; } #endif + +#if CONFIG_LUA_RTOS_LUA_USE_MQTT +static int msyslog_vprintf( const char *str, va_list l ) { + // Allocate space + char* tbuf = (char *)malloc(MAX_BUFF+1); + if (tbuf) { + int len = vsnprintf((char*)tbuf, MAX_BUFF, str, l); + + if (0 != logMQTT) { + lua_State *L = pvGetLuaState(); // Get the thread's Lua state + lua_rawgeti(L, LUA_REGISTRYINDEX, logMQTT); + lua_getfield(L, -1, "publish"); + lua_rawgeti(L, LUA_REGISTRYINDEX, logMQTT); + lua_pushstring(L, logTopic ? logTopic : "syslog"); + lua_pushlstring(L, tbuf, len); + lua_pushinteger(L, 0); + lua_pcall(L, 4, 0, 0); + } + + free(tbuf); + } + +#if CONFIG_LUA_RTOS_USE_RSYSLOG + if (0 != logSock) { + return rsyslog_vprintf( str, l ); + } +#endif + return vprintf( str, l ); +} + +int syslog_setlogmqtt (const int mqtt_ref, const char *topic) +{ + if (logMQTT) { + lua_State *L = pvGetLuaState(); // Get the thread's Lua state + luaL_unref(L, LUA_REGISTRYINDEX, logMQTT); + logMQTT = 0; + + esp_log_set_vprintf(vprintf); +#if CONFIG_LUA_RTOS_USE_RSYSLOG + if (0 != logSock) { + esp_log_set_vprintf(rsyslog_vprintf); + } +#endif + } + logMQTT = mqtt_ref; + + if (logTopic) { + free(logTopic); + logTopic = 0; + } + if (topic) { + logTopic = strdup(topic); + } + + if (logMQTT) { + esp_log_set_vprintf(msyslog_vprintf); + } + + return logMQTT; +} +int syslog_getlogmqtt () +{ + return logMQTT; +} +#endif +