source: trunk/libtransmission/log.c @ 14334

Last change on this file since 14334 was 14334, checked in by jordan, 8 years ago

mikedld patch: 4160-05b-file-fmt.patch

File size: 6.0 KB
Line 
1/*
2 * This file Copyright (C) 2010-2014 Mnemosyne LLC
3 *
4 * It may be used under the GNU GPL versions 2 or 3
5 * or any future license endorsed by Mnemosyne LLC.
6 *
7 * $Id: utils.c 13863 2013-01-24 23:59:52Z jordan $
8 */
9
10#include <assert.h>
11#include <errno.h>
12#include <stdio.h>
13#include <stdlib.h> /* getenv() */
14
15#include <event2/buffer.h>
16
17#include "transmission.h"
18#include "file.h"
19#include "log.h"
20#include "platform.h" /* tr_lock */
21#include "utils.h"
22
23tr_log_level __tr_message_level  = TR_LOG_ERROR;
24
25static bool           myQueueEnabled = false;
26static tr_log_message *  myQueue = NULL;
27static tr_log_message ** myQueueTail = &myQueue;
28static int            myQueueLength = 0;
29
30#ifndef _WIN32
31  /* make null versions of these win32 functions */
32  static inline int IsDebuggerPresent (void) { return false; }
33  static inline void OutputDebugStringA (const void * unused UNUSED) { }
34#endif
35
36/***
37****
38***/
39
40tr_log_level
41tr_logGetLevel (void)
42{
43  return __tr_message_level;
44}
45
46/***
47****
48***/
49
50static tr_lock*
51getMessageLock (void)
52{
53  static tr_lock * l = NULL;
54
55  if (!l)
56    l = tr_lockNew ();
57
58  return l;
59}
60
61tr_sys_file_t
62tr_logGetFile (void)
63{
64  static bool initialized = false;
65  static tr_sys_file_t file = TR_BAD_SYS_FILE;
66
67  if (!initialized)
68    {
69      int fd = 0;
70      const char * str = getenv ("TR_DEBUG_FD");
71
72      if (str && *str)
73        fd = atoi (str);
74
75      switch (fd)
76        {
77          case 1:
78            file = tr_sys_file_get_std (TR_STD_SYS_FILE_OUT, NULL);
79            break;
80
81          case 2:
82            file = tr_sys_file_get_std (TR_STD_SYS_FILE_ERR, NULL);
83            break;
84        }
85
86      initialized = true;
87    }
88
89  return file;
90}
91
92void
93tr_logSetLevel (tr_log_level level)
94{
95    __tr_message_level = level;
96}
97
98void
99tr_logSetQueueEnabled (bool isEnabled)
100{
101  assert (tr_isBool (isEnabled));
102
103  myQueueEnabled = isEnabled;
104}
105
106bool
107tr_logGetQueueEnabled (void)
108{
109  return myQueueEnabled;
110}
111
112tr_log_message *
113tr_logGetQueue (void)
114{
115  tr_log_message * ret;
116  tr_lockLock (getMessageLock ());
117
118  ret = myQueue;
119  myQueue = NULL;
120  myQueueTail = &myQueue;
121  myQueueLength = 0;
122
123  tr_lockUnlock (getMessageLock ());
124  return ret;
125}
126
127void
128tr_logFreeQueue (tr_log_message * list)
129{
130  tr_log_message * next;
131
132  while (NULL != list)
133    {
134      next = list->next;
135      tr_free (list->message);
136      tr_free (list->name);
137      tr_free (list);
138      list = next;
139    }
140}
141
142/**
143***
144**/
145
146char*
147tr_logGetTimeStr (char * buf, int buflen)
148{
149  char tmp[64];
150  struct tm now_tm;
151  struct timeval tv;
152  time_t seconds;
153  int milliseconds;
154
155  tr_gettimeofday (&tv);
156
157  seconds = tv.tv_sec;
158  tr_localtime_r (&seconds, &now_tm);
159  strftime (tmp, sizeof (tmp), "%Y-%m-%d %H:%M:%S.%%03d %Z", &now_tm); 
160  milliseconds = tv.tv_usec / 1000;
161  tr_snprintf (buf, buflen, tmp, milliseconds);
162
163  return buf;
164}
165
166bool
167tr_logGetDeepEnabled (void)
168{
169  static int8_t deepLoggingIsActive = -1;
170
171  if (deepLoggingIsActive < 0)
172    deepLoggingIsActive = IsDebuggerPresent () || (tr_logGetFile () != TR_BAD_SYS_FILE);
173
174  return deepLoggingIsActive != 0;
175}
176
177void
178tr_logAddDeep (const char  * file,
179               int           line,
180               const char  * name,
181               const char  * fmt,
182               ...)
183{
184  const tr_sys_file_t fp = tr_logGetFile ();
185  if (fp != TR_BAD_SYS_FILE || IsDebuggerPresent ())
186    {
187      va_list args;
188      char timestr[64];
189      char * message;
190      struct evbuffer * buf = evbuffer_new ();
191      char * base = tr_sys_path_basename (file, NULL);
192
193      evbuffer_add_printf (buf, "[%s] ",
194                           tr_logGetTimeStr (timestr, sizeof (timestr)));
195      if (name)
196        evbuffer_add_printf (buf, "%s ", name);
197      va_start (args, fmt);
198      evbuffer_add_vprintf (buf, fmt, args);
199      va_end (args);
200      evbuffer_add_printf (buf, " (%s:%d)", base, line);
201      /* FIXME (libevent2) ifdef this out for nonwindows platforms */
202      message = evbuffer_free_to_str (buf);
203      OutputDebugStringA (message);
204      OutputDebugStringA (TR_NATIVE_EOL_STR);
205      if (fp != TR_BAD_SYS_FILE)
206        tr_sys_file_write_line (fp, message, NULL);
207
208      tr_free (message);
209      tr_free (base);
210    }
211}
212
213/***
214****
215***/
216
217void
218tr_logAddMessage (const char * file,
219                  int line,
220                  tr_log_level level,
221                  const char * name,
222                  const char * fmt,
223                  ...)
224{
225  const int err = errno; /* message logging shouldn't affect errno */
226  char buf[1024];
227  va_list ap;
228  tr_lockLock (getMessageLock ());
229
230  /* build the text message */
231  *buf = '\0';
232  va_start (ap, fmt);
233  evutil_vsnprintf (buf, sizeof (buf), fmt, ap);
234  va_end (ap);
235
236  OutputDebugStringA (buf);
237
238  if (*buf)
239    {
240      if (tr_logGetQueueEnabled ())
241        {
242          tr_log_message * newmsg;
243          newmsg = tr_new0 (tr_log_message, 1);
244          newmsg->level = level;
245          newmsg->when = tr_time ();
246          newmsg->message = tr_strdup (buf);
247          newmsg->file = file;
248          newmsg->line = line;
249          newmsg->name = tr_strdup (name);
250
251          *myQueueTail = newmsg;
252          myQueueTail = &newmsg->next;
253          ++myQueueLength;
254
255          if (myQueueLength > TR_LOG_MAX_QUEUE_LENGTH)
256            {
257              tr_log_message * old = myQueue;
258              myQueue = old->next;
259              old->next = NULL;
260              tr_logFreeQueue (old);
261              --myQueueLength;
262              assert (myQueueLength == TR_LOG_MAX_QUEUE_LENGTH);
263            }
264        }
265      else
266        {
267          tr_sys_file_t fp;
268          char timestr[64];
269
270          fp = tr_logGetFile ();
271          if (fp == TR_BAD_SYS_FILE)
272            fp = tr_sys_file_get_std (TR_STD_SYS_FILE_ERR, NULL);
273
274          tr_logGetTimeStr (timestr, sizeof (timestr));
275
276          if (name)
277            tr_sys_file_write_fmt (fp, "[%s] %s: %s" TR_NATIVE_EOL_STR, NULL, timestr, name, buf);
278          else
279            tr_sys_file_write_fmt (fp, "[%s] %s" TR_NATIVE_EOL_STR, NULL, timestr, buf);
280          tr_sys_file_flush (fp, NULL);
281        }
282    }
283
284  tr_lockUnlock (getMessageLock ());
285  errno = err;
286}
Note: See TracBrowser for help on using the repository browser.