1 /* 2 * Copyright (c) 2006-2018, RT-Thread Development Team 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 * 6 * Change Logs: 7 * Date Author Notes 8 * 2018-09-07 armink the first version 9 */ 10 11 #include <stdarg.h> 12 #include <ulog.h> 13 #include <rthw.h> 14 #include "syslog.h" 15 16 #ifdef ULOG_OUTPUT_FLOAT 17 #include <stdio.h> 18 #endif 19 20 /* 21 * reference: 22 * http://pubs.opengroup.org/onlinepubs/7908799/xsh/syslog.h.html 23 * https://www.gnu.org/software/libc/manual/html_node/Submitting-Syslog-Messages.html 24 * http://man7.org/linux/man-pages/man3/syslog.3.html 25 */ 26 27 #ifdef ULOG_USING_SYSLOG 28 29 #include <sys/time.h> 30 31 #ifndef ULOG_SYSLOG_IDENT_MAX_LEN 32 #define ULOG_SYSLOG_IDENT_MAX_LEN ULOG_FILTER_TAG_MAX_LEN 33 #endif 34 35 static char local_ident[ULOG_SYSLOG_IDENT_MAX_LEN + 1]; 36 static int local_facility = LOG_USER; 37 static int local_option = LOG_USER; 38 static rt_bool_t is_open = RT_FALSE; 39 40 /** 41 * open connection to syslog 42 * 43 * @param ident is an arbitrary identification string which future syslog invocations will prefix to each message. 44 * @param option is not using on ulog. 45 * @param facility is the default facility code for this connection. 46 */ 47 void openlog(const char *ident, int option, int facility) 48 { 49 rt_base_t level; 50 51 ulog_init(); 52 53 level = rt_hw_interrupt_disable(); 54 55 rt_memset(local_ident, 0, sizeof(local_ident)); 56 if (ident) 57 { 58 rt_strncpy(local_ident, ident, ULOG_SYSLOG_IDENT_MAX_LEN); 59 } 60 else 61 { 62 rt_strncpy(local_ident, "rtt", ULOG_SYSLOG_IDENT_MAX_LEN); 63 } 64 65 local_option = option; 66 67 if (facility) 68 { 69 local_facility = facility; 70 } 71 else 72 { 73 /* default facility is LOG_USER */ 74 local_facility = LOG_USER; 75 } 76 /* output all level log */ 77 setlogmask(LOG_UPTO(LOG_DEBUG)); 78 79 is_open = RT_TRUE; 80 81 rt_hw_interrupt_enable(level); 82 83 } 84 85 /** 86 * This is functionally identical to syslog. 87 * 88 * @param priority log priority, can be generated by the macro LOG_MAKEPRI 89 * @param format log format 90 * @param args log arguments 91 */ 92 void vsyslog(int priority, const char *format, va_list args) 93 { 94 if (LOG_FAC(priority) == 0) 95 { 96 /* using local facility */ 97 priority |= local_facility; 98 } 99 100 ulog_voutput(priority, local_ident, RT_TRUE, format, args); 101 } 102 103 /** 104 * generates a log message 105 * 106 * @param priority log priority, can be generated by the macro LOG_MAKEPRI 107 * @param format log format, like printf() 108 */ 109 void syslog(int priority, const char *format, ...) 110 { 111 va_list args; 112 113 if (!is_open) 114 { 115 openlog(0, 0, 0); 116 } 117 /* args point to the first variable parameter */ 118 va_start(args, format); 119 120 vsyslog(priority, format, args); 121 122 va_end(args); 123 } 124 125 /** 126 * close the syslog 127 */ 128 void closelog(void) 129 { 130 ulog_deinit(); 131 132 is_open = RT_FALSE; 133 } 134 135 /** 136 * set log priority mask 137 * 138 * @param mask The log priority mask which generate by macro LOG_MASK and LOG_UPTO. 139 * 140 * @return This function returns the previous log priority mask. 141 */ 142 int setlogmask(int mask) 143 { 144 static int old_mask = 0; 145 int return_mask = old_mask; 146 147 ulog_tag_lvl_filter_set(local_ident, mask); 148 149 old_mask = mask; 150 151 return return_mask; 152 } 153 154 static const char *get_month_str(uint8_t month) 155 { 156 switch(month) 157 { 158 case 1: return "Jan"; 159 case 2: return "Feb"; 160 case 3: return "Mar"; 161 case 4: return "Apr"; 162 case 5: return "May"; 163 case 6: return "June"; 164 case 7: return "July"; 165 case 8: return "Aug"; 166 case 9: return "Sept"; 167 case 10: return "Oct"; 168 case 11: return "Nov"; 169 case 12: return "Dec"; 170 default: return "Unknown"; 171 } 172 } 173 174 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) 175 { 176 extern size_t ulog_strcpy(size_t cur_len, char *dst, const char *src); 177 178 rt_size_t log_len = 0, newline_len = rt_strlen(ULOG_NEWLINE_SIGN); 179 int fmt_result; 180 181 RT_ASSERT(log_buf); 182 RT_ASSERT(LOG_PRI(level) <= LOG_DEBUG); 183 RT_ASSERT(tag); 184 RT_ASSERT(format); 185 186 /* add time and priority (level) info */ 187 { 188 time_t now = time(RT_NULL); 189 struct tm *tm, tm_tmp; 190 191 tm = gmtime_r(&now, &tm_tmp); 192 193 #ifdef ULOG_OUTPUT_LEVEL 194 rt_snprintf(log_buf + log_len, ULOG_LINE_BUF_SIZE - log_len, "<%d>%s%3d %02d:%02d:%02d", level, 195 get_month_str(tm->tm_mon + 1), tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, rt_tick_get() % 1000); 196 #else 197 rt_snprintf(log_buf + log_len, ULOG_LINE_BUF_SIZE - log_len, "%s%3d %02d:%02d:%02d", 198 get_month_str(tm->tm_mon + 1), tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, rt_tick_get() % 1000); 199 #endif /* ULOG_OUTPUT_LEVEL */ 200 201 log_len += rt_strlen(log_buf + log_len); 202 } 203 204 #ifdef ULOG_OUTPUT_TAG 205 /* add identification (tag) info */ 206 { 207 log_len += ulog_strcpy(log_len, log_buf + log_len, " "); 208 log_len += ulog_strcpy(log_len, log_buf + log_len, tag); 209 } 210 #endif /* ULOG_OUTPUT_TAG */ 211 212 #ifdef ULOG_OUTPUT_THREAD_NAME 213 /* add thread info */ 214 { 215 log_len += ulog_strcpy(log_len, log_buf + log_len, " "); 216 /* is not in interrupt context */ 217 if (rt_interrupt_get_nest() == 0) 218 { 219 log_len += ulog_strcpy(log_len, log_buf + log_len, rt_thread_self()->name); 220 } 221 else 222 { 223 log_len += ulog_strcpy(log_len, log_buf + log_len, "ISR"); 224 } 225 } 226 #endif /* ULOG_OUTPUT_THREAD_NAME */ 227 228 log_len += ulog_strcpy(log_len, log_buf + log_len, ": "); 229 230 #ifdef ULOG_OUTPUT_FLOAT 231 fmt_result = vsnprintf(log_buf + log_len, ULOG_LINE_BUF_SIZE - log_len, format, args); 232 #else 233 fmt_result = rt_vsnprintf(log_buf + log_len, ULOG_LINE_BUF_SIZE - log_len, format, args); 234 #endif /* ULOG_OUTPUT_FLOAT */ 235 236 /* calculate log length */ 237 if ((log_len + fmt_result <= ULOG_LINE_BUF_SIZE) && (fmt_result > -1)) 238 { 239 log_len += fmt_result; 240 } 241 else 242 { 243 /* using max length */ 244 log_len = ULOG_LINE_BUF_SIZE; 245 } 246 247 /* overflow check and reserve some space for newline sign */ 248 if (log_len + newline_len > ULOG_LINE_BUF_SIZE) 249 { 250 /* using max length */ 251 log_len = ULOG_LINE_BUF_SIZE; 252 /* reserve some space for newline sign */ 253 log_len -= newline_len; 254 } 255 256 /* package newline sign */ 257 if (newline) 258 { 259 log_len += ulog_strcpy(log_len, log_buf + log_len, ULOG_NEWLINE_SIGN); 260 } 261 262 return log_len; 263 } 264 265 #endif /* ULOG_USING_SYSLOG */ 266