xref: /nrf52832-nimble/rt-thread/components/utilities/ulog/syslog/syslog.c (revision 167494296f0543431a51b6b1b83e957045294e05)
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