debug_level 3 now prints seconds since start of openocd
[fw/openocd] / src / helper / log.c
1 /***************************************************************************\r
2  *   Copyright (C) 2005 by Dominic Rath                                    *\r
3  *   Dominic.Rath@gmx.de                                                   *\r
4  *                                                                         *\r
5  *   This program is free software; you can redistribute it and/or modify  *\r
6  *   it under the terms of the GNU General Public License as published by  *\r
7  *   the Free Software Foundation; either version 2 of the License, or     *\r
8  *   (at your option) any later version.                                   *\r
9  *                                                                         *\r
10  *   This program is distributed in the hope that it will be useful,       *\r
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\r
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\r
13  *   GNU General Public License for more details.                          *\r
14  *                                                                         *\r
15  *   You should have received a copy of the GNU General Public License     *\r
16  *   along with this program; if not, write to the                         *\r
17  *   Free Software Foundation, Inc.,                                       *\r
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *\r
19  ***************************************************************************/\r
20 #ifdef HAVE_CONFIG_H\r
21 #include "config.h"\r
22 #endif\r
23 \r
24 #include "log.h"\r
25 #include "configuration.h"\r
26 \r
27 #include <stdio.h>\r
28 #include <stdlib.h>\r
29 #include <string.h>\r
30 #include <stdarg.h>\r
31 #include <time.h>\r
32 \r
33 int debug_level = -1;\r
34 \r
35 static FILE* log_output;\r
36 \r
37 static void *privData;\r
38 static logCallback callback;\r
39 static time_t start;\r
40 \r
41 void log_setCallback(logCallback c, void *p)\r
42 {\r
43         callback = c;\r
44         privData = p;\r
45 }\r
46 \r
47 static char *log_strings[5] = \r
48 {\r
49         "User:   ",\r
50         "Error:  ",\r
51         "Warning:",\r
52         "Info:   ",\r
53         "Debug:  "\r
54 };\r
55 \r
56 void log_printf(enum log_levels level, const char *file, int line, const char *function, const char *format, ...)\r
57 {\r
58         static int count = 0;\r
59         count++;\r
60         va_list args;\r
61         char buffer[512];\r
62 \r
63         if (level > debug_level)\r
64                 return;\r
65 \r
66         va_start(args, format);\r
67         vsnprintf(buffer, 512, format, args);\r
68 \r
69         char *f = strrchr(file, '/');\r
70         if (f != NULL)\r
71                 file = f + 1;\r
72 \r
73         if (debug_level >= LOG_DEBUG)\r
74         {\r
75                 /* print with count and time information */\r
76                 time_t t=time(NULL)-start;\r
77                 fprintf(log_output, "%s %d %ld %s:%d %s(): %s\n", log_strings[level+1], count, t, file, line, function, buffer);\r
78         }\r
79         else\r
80         {\r
81                 /* do not print count and time */\r
82                 fprintf(log_output, "%s %s:%d %s(): %s\n", log_strings[level+1], file, line, function, buffer);\r
83         }\r
84 \r
85         fflush(log_output);\r
86         \r
87         va_end(args);\r
88 \r
89         /* Never forward LOG_DEBUG, too verbose and they can be found in the log if need be */\r
90         if (callback && (level <= LOG_INFO))\r
91         {\r
92                 va_start(args, format);\r
93                 callback(privData, file, line, function, format, args);\r
94                 va_end(args);\r
95         }\r
96 }\r
97 \r
98 /* change the current debug level on the fly\r
99  * 0: only ERRORS\r
100  * 1: + WARNINGS\r
101  * 2: + INFORMATIONAL MSGS\r
102  * 3: + DEBUG MSGS\r
103  */\r
104 int handle_debug_level_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
105 {\r
106         if (argc == 0)\r
107                 command_print(cmd_ctx, "debug_level: %i", debug_level);\r
108 \r
109         if (argc > 0)\r
110                 debug_level = strtoul(args[0], NULL, 0);\r
111 \r
112         if (debug_level < 0)\r
113                 debug_level = 0;\r
114 \r
115         if (debug_level > 3)\r
116                 debug_level = 3;\r
117 \r
118         return ERROR_OK;\r
119 }\r
120 \r
121 int handle_log_output_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
122 {\r
123         if (argc == 1)\r
124         {\r
125                 FILE* file = fopen(args[0], "w");\r
126                 \r
127                 if (file)\r
128                 {\r
129                         log_output = file;\r
130                 }\r
131         }\r
132 \r
133         return ERROR_OK;\r
134 }\r
135 \r
136 int log_register_commands(struct command_context_s *cmd_ctx)\r
137 {\r
138         start = time(NULL);\r
139         register_command(cmd_ctx, NULL, "log_output", handle_log_output_command,\r
140                 COMMAND_ANY, "redirect logging to <file> (default: stderr)");\r
141         register_command(cmd_ctx, NULL, "debug_level", handle_debug_level_command,\r
142                 COMMAND_ANY, "adjust debug level <0-3>");\r
143 \r
144         return ERROR_OK;\r
145 }\r
146 \r
147 int log_init(struct command_context_s *cmd_ctx)\r
148 {\r
149         /* set defaults for daemon configuration, if not set by cmdline or cfgfile */\r
150         if (debug_level == -1)\r
151                 debug_level = LOG_INFO;\r
152         \r
153         if (log_output == NULL)\r
154         {\r
155                 log_output = stderr;\r
156         }\r
157         \r
158         return ERROR_OK;\r
159 }\r
160         \r
161 int set_log_output(struct command_context_s *cmd_ctx, FILE *output)\r
162 {\r
163         log_output = output;\r
164         return ERROR_OK;\r
165 }\r
166 \r
167 /* return allocated string w/printf() result */\r
168 char *allocPrintf(const char *fmt, va_list ap)\r
169 {\r
170         char *string = NULL;\r
171         \r
172         /* start by 0 to exercise all the code paths. Need minimum 2 bytes to\r
173          * fit 1 char and 0 terminator. */\r
174         int size = 0;\r
175         int first = 1;\r
176         for (;;)\r
177         {\r
178                 if ((string == NULL) || (!first))\r
179                 {\r
180                         size = size * 2 + 2;\r
181                         char *t = string;\r
182                         string = realloc(string, size);\r
183                         if (string == NULL)\r
184                         {\r
185                                 if (t != NULL)\r
186                                         free(t);\r
187                                 return NULL;\r
188                         }\r
189                 }\r
190         \r
191             int ret;\r
192             ret = vsnprintf(string, size, fmt, ap);\r
193             /* NB! The result of the vsnprintf() might be an *EMPTY* string! */\r
194             if ((ret >= 0) && ((ret + 1) < size))\r
195             {\r
196                 return string;\r
197             }\r
198             /* there was just enough or not enough space, allocate more. */\r
199             first = 0;\r
200         }\r
201 }\r