log.c (7600B)
1 /* 2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client 3 * Copyright (C) 1999-2021 the Claws Mail team and Hiroyuki Yamamoto 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 #include "defs.h" 21 22 #include <glib.h> 23 #include <glib/gi18n.h> 24 25 #include "utils.h" 26 #include "log.h" 27 #include "hooks.h" 28 #include "file-utils.h" 29 30 #define FWRITE(_b,_s,_n,_f) if (fwrite(_b,_s,_n,_f) != _n) { \ 31 g_message("log fwrite failed!\n"); \ 32 return; \ 33 } 34 #define FPUTS(_b,_f) if (fputs(_b,_f) == EOF) { \ 35 g_message("log fputs failed!\n"); \ 36 return; \ 37 } 38 #define FFLUSH(_f) if (fflush(_f) != 0) { \ 39 g_message("log fflush failed!\n"); \ 40 return; \ 41 } 42 43 static FILE *log_fp[LOG_INSTANCE_MAX] = { 44 NULL, 45 NULL 46 }; 47 48 static size_t log_size[LOG_INSTANCE_MAX] = { 49 0, 50 0 51 }; 52 53 static gchar *log_filename[LOG_INSTANCE_MAX] = { 54 NULL, 55 NULL 56 }; 57 58 /* read-only */ 59 static gboolean log_error_capability[LOG_INSTANCE_MAX] = { 60 TRUE, 61 FALSE 62 }; 63 64 typedef struct _LogInstanceData LogInstanceData; 65 66 struct _LogInstanceData { 67 const char *hook; 68 gchar *title; 69 int *prefs_logwin_width; 70 int *prefs_logwin_height; 71 }; 72 73 static LogInstanceData log_instances[LOG_INSTANCE_MAX] = { 74 { LOG_APPEND_TEXT_HOOKLIST, NULL, NULL, NULL }, 75 { DEBUG_FILTERING_APPEND_TEXT_HOOKLIST, NULL, NULL, NULL } 76 }; 77 78 static gboolean invoke_hook_cb (gpointer data) 79 { 80 LogText *logtext = (LogText *)data; 81 hooks_invoke(get_log_hook(logtext->instance), logtext); 82 g_free(logtext->text); 83 g_free(logtext); 84 return FALSE; 85 } 86 87 void set_log_file(LogInstance instance, const gchar *filename) 88 { 89 gchar *fullname = NULL; 90 if (log_fp[instance]) 91 return; 92 93 if (!g_path_is_absolute(filename)) { 94 fullname = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, 95 filename, NULL); 96 } else { 97 fullname = g_strdup(filename); 98 } 99 /* backup old logfile if existing */ 100 if (is_file_exist(fullname)) { 101 gchar *backupname; 102 103 backupname = g_strconcat(fullname, ".bak", NULL); 104 unlink(backupname); 105 if (g_rename(fullname, backupname) < 0) 106 FILE_OP_ERROR(fullname, "rename"); 107 g_free(backupname); 108 } 109 110 log_fp[instance] = fopen(fullname, "wb"); 111 if (!log_fp[instance]) { 112 FILE_OP_ERROR(fullname, "fopen"); 113 log_filename[instance] = NULL; 114 g_free(fullname); 115 return; 116 } 117 118 log_filename[instance] = g_strdup(fullname); 119 log_size[instance] = 0; 120 g_free(fullname); 121 } 122 123 void close_log_file(LogInstance instance) 124 { 125 if (log_fp[instance]) { 126 fclose(log_fp[instance]); 127 log_fp[instance] = NULL; 128 log_size[instance] = 0; 129 g_free(log_filename[instance]); 130 log_filename[instance] = NULL; 131 } 132 } 133 134 static void rotate_log(LogInstance instance) 135 { 136 if (log_size[instance] > 10 * 1024* 1024) { 137 gchar *filename = g_strdup(log_filename[instance]); 138 debug_print("rotating %s\n", filename); 139 close_log_file(instance); 140 set_log_file(instance, filename); 141 g_free(filename); 142 } 143 } 144 145 const char *get_log_hook(LogInstance instance) 146 { 147 return log_instances[instance].hook; 148 } 149 150 void set_log_title(LogInstance instance, gchar *title) 151 { 152 log_instances[instance].title = title; 153 } 154 155 gchar *get_log_title(LogInstance instance) 156 { 157 return log_instances[instance].title; 158 } 159 160 void set_log_prefs(LogInstance instance, int* logwin_width, int* logwin_height) 161 { 162 log_instances[instance].prefs_logwin_width = logwin_width; 163 log_instances[instance].prefs_logwin_height = logwin_height; 164 } 165 166 void get_log_prefs(LogInstance instance, int** logwin_width, int** logwin_height) 167 { 168 if (logwin_width) 169 *logwin_width = log_instances[instance].prefs_logwin_width; 170 if (logwin_height) 171 *logwin_height = log_instances[instance].prefs_logwin_height; 172 } 173 174 gboolean get_log_error_capability(LogInstance instance) 175 { 176 return log_error_capability[instance]; 177 178 } 179 180 void log_print(LogInstance instance, const gchar *format, ...) 181 { 182 va_list args; 183 gchar buf[BUFFSIZE + LOG_TIME_LEN]; 184 time_t t; 185 LogText *logtext = g_new0(LogText, 1); 186 struct tm buft; 187 188 time(&t); 189 strftime(buf, LOG_TIME_LEN + 1, LOG_TIME_FORMAT, localtime_r(&t, &buft)); 190 191 va_start(args, format); 192 g_vsnprintf(buf + LOG_TIME_LEN, BUFFSIZE, format, args); 193 va_end(args); 194 195 if (debug_get_mode()) g_print("%s", buf); 196 197 logtext->instance = instance; 198 logtext->text = g_strdup(buf); 199 logtext->type = LOG_NORMAL; 200 201 g_timeout_add(0, invoke_hook_cb, logtext); 202 203 if (log_fp[instance]) { 204 FPUTS(buf, log_fp[instance]) 205 log_size[instance] += strlen(buf); 206 FFLUSH(log_fp[instance]) 207 rotate_log(instance); 208 } 209 } 210 211 void log_message(LogInstance instance, const gchar *format, ...) 212 { 213 va_list args; 214 gchar buf[BUFFSIZE + LOG_TIME_LEN]; 215 time_t t; 216 LogText *logtext = g_new0(LogText, 1); 217 struct tm buft; 218 219 time(&t); 220 strftime(buf, LOG_TIME_LEN + 1, LOG_TIME_FORMAT, localtime_r(&t, &buft)); 221 222 va_start(args, format); 223 g_vsnprintf(buf + LOG_TIME_LEN, BUFFSIZE, format, args); 224 va_end(args); 225 226 if (debug_get_mode()) g_message("%s", buf + LOG_TIME_LEN); 227 228 logtext->instance = instance; 229 logtext->text = g_strdup(buf + LOG_TIME_LEN); 230 logtext->type = LOG_MSG; 231 232 g_timeout_add(0, invoke_hook_cb, logtext); 233 234 if (log_fp[instance]) { 235 FWRITE(buf, 1, LOG_TIME_LEN, log_fp[instance]) 236 FPUTS("* message: ", log_fp[instance]) 237 log_size[instance] += strlen("* message: "); 238 FPUTS(buf + LOG_TIME_LEN, log_fp[instance]) 239 log_size[instance] += strlen(buf); 240 FFLUSH(log_fp[instance]) 241 rotate_log(instance); 242 } 243 } 244 245 void log_warning(LogInstance instance, const gchar *format, ...) 246 { 247 va_list args; 248 gchar buf[BUFFSIZE + LOG_TIME_LEN]; 249 time_t t; 250 LogText *logtext = g_new0(LogText, 1); 251 struct tm buft; 252 253 time(&t); 254 strftime(buf, LOG_TIME_LEN + 1, LOG_TIME_FORMAT, localtime_r(&t, &buft)); 255 256 va_start(args, format); 257 g_vsnprintf(buf + LOG_TIME_LEN, BUFFSIZE, format, args); 258 va_end(args); 259 260 g_warning("%s", buf); 261 262 logtext->instance = instance; 263 logtext->text = g_strdup(buf + LOG_TIME_LEN); 264 logtext->type = LOG_WARN; 265 266 g_timeout_add(0, invoke_hook_cb, logtext); 267 268 if (log_fp[instance]) { 269 FWRITE(buf, 1, LOG_TIME_LEN, log_fp[instance]) 270 FPUTS("** warning: ", log_fp[instance]) 271 log_size[instance] += strlen("** warning: "); 272 FPUTS(buf + LOG_TIME_LEN, log_fp[instance]) 273 log_size[instance] += strlen(buf); 274 FFLUSH(log_fp[instance]) 275 rotate_log(instance); 276 } 277 } 278 279 void log_error(LogInstance instance, const gchar *format, ...) 280 { 281 va_list args; 282 gchar buf[BUFFSIZE + LOG_TIME_LEN]; 283 time_t t; 284 LogText *logtext = g_new0(LogText, 1); 285 struct tm buft; 286 287 time(&t); 288 strftime(buf, LOG_TIME_LEN + 1, LOG_TIME_FORMAT, localtime_r(&t, &buft)); 289 290 va_start(args, format); 291 g_vsnprintf(buf + LOG_TIME_LEN, BUFFSIZE, format, args); 292 va_end(args); 293 294 g_warning("%s", buf); 295 296 logtext->instance = instance; 297 logtext->text = g_strdup(buf + LOG_TIME_LEN); 298 logtext->type = LOG_ERROR; 299 300 g_timeout_add(0, invoke_hook_cb, logtext); 301 302 if (log_fp[instance]) { 303 FWRITE(buf, 1, LOG_TIME_LEN, log_fp[instance]) 304 FPUTS("*** error: ", log_fp[instance]) 305 log_size[instance] += strlen("*** error: "); 306 FPUTS(buf + LOG_TIME_LEN, log_fp[instance]) 307 log_size[instance] += strlen(buf); 308 FFLUSH(log_fp[instance]) 309 rotate_log(instance); 310 } 311 } 312 313 #undef FWRITE 314 #undef FPUTS 315 #undef FFLUSH 316