263 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			263 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|  | /*
 | ||
|  |  * Copyright (c) 2006-2022, RT-Thread Development Team | ||
|  |  * | ||
|  |  * SPDX-License-Identifier: Apache-2.0 | ||
|  |  * | ||
|  |  * Change Logs: | ||
|  |  * Date           Author       Notes | ||
|  |  * 2018-09-07     armink       the first version | ||
|  |  */ | ||
|  | 
 | ||
|  | #include <stdarg.h>
 | ||
|  | #include <ulog.h>
 | ||
|  | #include <rthw.h>
 | ||
|  | #include <stdint.h>
 | ||
|  | #include "syslog.h"
 | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * reference: | ||
|  |  * http://pubs.opengroup.org/onlinepubs/7908799/xsh/syslog.h.html
 | ||
|  |  * https://www.gnu.org/software/libc/manual/html_node/Submitting-Syslog-Messages.html
 | ||
|  |  * http://man7.org/linux/man-pages/man3/syslog.3.html
 | ||
|  |  */ | ||
|  | 
 | ||
|  | #ifdef ULOG_USING_SYSLOG
 | ||
|  | 
 | ||
|  | #include <sys/time.h>
 | ||
|  | 
 | ||
|  | #ifndef ULOG_SYSLOG_IDENT_MAX_LEN
 | ||
|  | #define ULOG_SYSLOG_IDENT_MAX_LEN      ULOG_FILTER_TAG_MAX_LEN
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | static char local_ident[ULOG_SYSLOG_IDENT_MAX_LEN + 1]; | ||
|  | static int local_facility = LOG_USER; | ||
|  | static int local_option = LOG_USER; | ||
|  | static rt_bool_t is_open = RT_FALSE; | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * open connection to syslog | ||
|  |  * | ||
|  |  * @param ident is an arbitrary identification string which future syslog invocations will prefix to each message. | ||
|  |  * @param option is not using on ulog. | ||
|  |  * @param facility is the default facility code for this connection. | ||
|  |  */ | ||
|  | void openlog(const char *ident, int option, int facility) | ||
|  | { | ||
|  |     rt_base_t level; | ||
|  | 
 | ||
|  |     ulog_init(); | ||
|  | 
 | ||
|  |     level = rt_hw_interrupt_disable(); | ||
|  | 
 | ||
|  |     rt_memset(local_ident, 0, sizeof(local_ident)); | ||
|  |     if (ident) | ||
|  |     { | ||
|  |         rt_strncpy(local_ident, ident, ULOG_SYSLOG_IDENT_MAX_LEN); | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |         rt_strncpy(local_ident, "rtt", ULOG_SYSLOG_IDENT_MAX_LEN); | ||
|  |     } | ||
|  | 
 | ||
|  |     local_option = option; | ||
|  | 
 | ||
|  |     if (facility) | ||
|  |     { | ||
|  |         local_facility = facility; | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |         /* default facility is LOG_USER */ | ||
|  |         local_facility = LOG_USER; | ||
|  |     } | ||
|  |     /* output all level log */ | ||
|  |     setlogmask(LOG_UPTO(LOG_DEBUG)); | ||
|  | 
 | ||
|  |     is_open = RT_TRUE; | ||
|  | 
 | ||
|  |     rt_hw_interrupt_enable(level); | ||
|  | 
 | ||
|  | } | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * This is functionally identical to syslog. | ||
|  |  * | ||
|  |  * @param priority log priority, can be generated by the macro LOG_MAKEPRI | ||
|  |  * @param format log format | ||
|  |  * @param args log arguments | ||
|  |  */ | ||
|  | void vsyslog(int priority, const char *format, va_list args) | ||
|  | { | ||
|  |     if (LOG_FAC(priority) == 0) | ||
|  |     { | ||
|  |         /* using local facility */ | ||
|  |         priority |= local_facility; | ||
|  |     } | ||
|  | 
 | ||
|  |     ulog_voutput(priority, local_ident, RT_TRUE, format, args); | ||
|  | } | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * generates a log message | ||
|  |  * | ||
|  |  * @param priority log priority, can be generated by the macro LOG_MAKEPRI | ||
|  |  * @param format log format, like printf() | ||
|  |  */ | ||
|  | void syslog(int priority, const char *format, ...) | ||
|  | { | ||
|  |     va_list args; | ||
|  | 
 | ||
|  |     if (!is_open) | ||
|  |     { | ||
|  |         openlog(0, 0, 0); | ||
|  |     } | ||
|  |     /* args point to the first variable parameter */ | ||
|  |     va_start(args, format); | ||
|  | 
 | ||
|  |     vsyslog(priority, format, args); | ||
|  | 
 | ||
|  |     va_end(args); | ||
|  | } | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * close the syslog | ||
|  |  */ | ||
|  | void closelog(void) | ||
|  | { | ||
|  |     ulog_deinit(); | ||
|  | 
 | ||
|  |     is_open = RT_FALSE; | ||
|  | } | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * set log priority mask | ||
|  |  * | ||
|  |  * @param mask The log priority mask which generate by macro LOG_MASK and LOG_UPTO. | ||
|  |  * | ||
|  |  * @return This function returns the previous log priority mask. | ||
|  |  */ | ||
|  | int setlogmask(int mask) | ||
|  | { | ||
|  |     static int old_mask = 0; | ||
|  |     int return_mask = old_mask; | ||
|  | 
 | ||
|  |     ulog_tag_lvl_filter_set(local_ident, mask); | ||
|  | 
 | ||
|  |     old_mask = mask; | ||
|  | 
 | ||
|  |     return return_mask; | ||
|  | } | ||
|  | 
 | ||
|  | static const char *get_month_str(uint8_t month) | ||
|  | { | ||
|  |     switch(month) | ||
|  |     { | ||
|  |     case 1: return "Jan"; | ||
|  |     case 2: return "Feb"; | ||
|  |     case 3: return "Mar"; | ||
|  |     case 4: return "Apr"; | ||
|  |     case 5: return "May"; | ||
|  |     case 6: return "June"; | ||
|  |     case 7: return "July"; | ||
|  |     case 8: return "Aug"; | ||
|  |     case 9: return "Sept"; | ||
|  |     case 10: return "Oct"; | ||
|  |     case 11: return "Nov"; | ||
|  |     case 12: return "Dec"; | ||
|  |     default: return "Unknown"; | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | rt_weak rt_size_t syslog_formater(char *log_buf, int level, const char *tag, rt_bool_t newline, const char *format, va_list args) | ||
|  | { | ||
|  |     extern rt_size_t ulog_strcpy(rt_size_t cur_len, char *dst, const char *src); | ||
|  | 
 | ||
|  |     rt_size_t log_len = 0, newline_len = rt_strlen(ULOG_NEWLINE_SIGN); | ||
|  |     int fmt_result; | ||
|  | 
 | ||
|  |     RT_ASSERT(log_buf); | ||
|  |     RT_ASSERT(LOG_PRI(level) <= LOG_DEBUG); | ||
|  |     RT_ASSERT(tag); | ||
|  |     RT_ASSERT(format); | ||
|  | 
 | ||
|  |     /* add time and priority (level) info */ | ||
|  |     { | ||
|  |         time_t now = time(RT_NULL); | ||
|  |         struct tm *tm, tm_tmp; | ||
|  | 
 | ||
|  |         tm = gmtime_r(&now, &tm_tmp); | ||
|  | 
 | ||
|  | #ifdef ULOG_OUTPUT_LEVEL
 | ||
|  |         rt_snprintf(log_buf + log_len, ULOG_LINE_BUF_SIZE - log_len, "<%d>%s%3d %02d:%02d:%02d", level, | ||
|  |                 get_month_str(tm->tm_mon + 1), tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); | ||
|  | #else
 | ||
|  |         rt_snprintf(log_buf + log_len, ULOG_LINE_BUF_SIZE - log_len, "%s%3d %02d:%02d:%02d", | ||
|  |                 get_month_str(tm->tm_mon + 1), tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); | ||
|  | #endif /* ULOG_OUTPUT_LEVEL */
 | ||
|  | 
 | ||
|  |         log_len += rt_strlen(log_buf + log_len); | ||
|  |     } | ||
|  | 
 | ||
|  | #ifdef ULOG_OUTPUT_TAG
 | ||
|  |     /* add identification (tag) info */ | ||
|  |     { | ||
|  |         log_len += ulog_strcpy(log_len, log_buf + log_len, " "); | ||
|  |         log_len += ulog_strcpy(log_len, log_buf + log_len, tag); | ||
|  |     } | ||
|  | #endif /* ULOG_OUTPUT_TAG */
 | ||
|  | 
 | ||
|  | #ifdef ULOG_OUTPUT_THREAD_NAME
 | ||
|  |     /* add thread info */ | ||
|  |     { | ||
|  |         log_len += ulog_strcpy(log_len, log_buf + log_len, " "); | ||
|  |         /* is not in interrupt context */ | ||
|  |         if (rt_interrupt_get_nest() == 0) | ||
|  |         { | ||
|  |             log_len += ulog_strcpy(log_len, log_buf + log_len, rt_thread_self()->parent.name); | ||
|  |         } | ||
|  |         else | ||
|  |         { | ||
|  |             log_len += ulog_strcpy(log_len, log_buf + log_len, "ISR"); | ||
|  |         } | ||
|  |     } | ||
|  | #endif /* ULOG_OUTPUT_THREAD_NAME */
 | ||
|  | 
 | ||
|  |     log_len += ulog_strcpy(log_len, log_buf + log_len, ": "); | ||
|  |     fmt_result = rt_vsnprintf(log_buf + log_len, ULOG_LINE_BUF_SIZE - log_len, format, args); | ||
|  | 
 | ||
|  |     /* calculate log length */ | ||
|  |     if ((log_len + fmt_result <= ULOG_LINE_BUF_SIZE) && (fmt_result > -1)) | ||
|  |     { | ||
|  |         log_len += fmt_result; | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |         /* using max length */ | ||
|  |         log_len = ULOG_LINE_BUF_SIZE; | ||
|  |     } | ||
|  | 
 | ||
|  |     /* overflow check and reserve some space for newline sign and string end sign */ | ||
|  |     if (log_len + newline_len + sizeof('\0') > ULOG_LINE_BUF_SIZE) | ||
|  |     { | ||
|  |         /* using max length */ | ||
|  |         log_len = ULOG_LINE_BUF_SIZE; | ||
|  |         /* reserve some space for newline sign */ | ||
|  |         log_len -= newline_len; | ||
|  |         /* reserve some space for string end sign */ | ||
|  |         log_len -= sizeof('\0'); | ||
|  |     } | ||
|  | 
 | ||
|  |     /* package newline sign */ | ||
|  |     if (newline) | ||
|  |     { | ||
|  |         log_len += ulog_strcpy(log_len, log_buf + log_len, ULOG_NEWLINE_SIGN); | ||
|  |     } | ||
|  | 
 | ||
|  |     /* add string end sign */ | ||
|  |     log_buf[log_len] = '\0'; | ||
|  | 
 | ||
|  |     return log_len; | ||
|  | } | ||
|  | 
 | ||
|  | #endif /* ULOG_USING_SYSLOG */
 |