source: trunk/libtransmission/log.c @ 14336

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

(trunk) #4160: mike.dld patch: 4160-07-env.patch

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