NCBI C++ ToolKit
log.c
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Brian Bruns
3  * Copyright (C) 2006-2015 Frediano Ziglio
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library 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 GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20 
21 #include <config.h>
22 
23 #include <stdarg.h>
24 
25 #include <freetds/time.h>
26 
27 #include <assert.h>
28 #include <ctype.h>
29 #include <limits.h>
30 #include <stdio.h>
31 
32 #if HAVE_STDLIB_H
33 #include <stdlib.h>
34 #endif /* HAVE_STDLIB_H */
35 
36 #if HAVE_STRING_H
37 #include <string.h>
38 #endif /* HAVE_STRING_H */
39 
40 #if HAVE_UNISTD_H
41 #include <unistd.h>
42 #endif /* HAVE_UNISTD_H */
43 
44 #ifdef _WIN32
45 # include <process.h>
46 #endif
47 
48 #include <freetds/tds.h>
49 #include <freetds/checks.h>
50 #include <freetds/thread.h>
51 
52 /* for now all messages go to the log */
55 static char *g_dump_filename = NULL;
56 /** Tell if TDS debug logging is turned on or off */
58 #ifdef NCBI_TLS_VAR
60 #endif
62 static FILE *g_dumpfile = NULL; /* file pointer for dump log */
63 #ifdef TDS_HAVE_MUTEX
65 #endif
66 
67 static FILE* tdsdump_append(void);
68 
69 #ifdef TDS_ATTRIBUTE_DESTRUCTOR
70 static void __attribute__((destructor))
71 tds_util_deinit(void)
72 {
73  tdsdump_close();
74 }
75 #endif
76 
77 /**
78  * Temporarily turn off logging.
79  */
80 void
82 {
84  tds_write_dump = 0;
86 } /* tdsdump_off() */
87 
88 
89 /**
90  * Turn logging back on. You must call tdsdump_open() before calling this routine.
91  */
92 void
94 {
96  if (tdsdump_isopen())
97  tds_write_dump = 1;
99 }
100 
101 /**
102  * Get the logging state.
103  */
104 int
106 {
107  return tds_write_dump;
108 }
109 
110 int
112 {
113  return g_dumpfile || g_dump_filename;
114 }
115 
116 
117 /**
118  * Create and truncate a human readable dump file for the TDS
119  * traffic. The name of the file is specified by the filename
120  * parameter. If that is given as NULL or an empty string,
121  * any existing log file will be closed.
122  *
123  * \return true if the file was opened, false if it couldn't be opened.
124  */
125 int
126 tdsdump_open(const char *filename)
127 {
128  int result; /* really should be a boolean, not an int */
129 
131 
132  /* same append file */
133  if (tds_g_append_mode && filename != NULL && g_dump_filename != NULL && strcmp(filename, g_dump_filename) == 0) {
135  return 1;
136  }
137 
138  tds_write_dump = 0;
139 
140  /* free old one */
141  if (g_dumpfile != NULL && g_dumpfile != stdout && g_dumpfile != stderr)
142  fclose(g_dumpfile);
143  g_dumpfile = NULL;
144  if (g_dump_filename)
146 
147  /* required to close just log ?? */
148  if (filename == NULL || filename[0] == '\0') {
150  return 1;
151  }
152 
153  result = 1;
154  if (tds_g_append_mode) {
155  g_dump_filename = strdup(filename);
156  /* if mutex are available do not reopen file every time */
157 #ifdef TDS_HAVE_MUTEX
159 #endif
160  } else if (!strcmp(filename, "stdout")) {
161  g_dumpfile = stdout;
162  } else if (!strcmp(filename, "stderr")) {
163  g_dumpfile = stderr;
164  } else if (NULL == (g_dumpfile = fopen(filename, "w"))) {
165  result = 0;
166  }
167 
168  if (result)
169  tds_write_dump = 1;
171 
172  if (result) {
173  char today[64];
174  struct tm res;
175  time_t t;
176 
177  time(&t);
178  today[0] = 0;
179  if (tds_localtime_r(&t, &res))
180  strftime(today, sizeof(today), "%Y-%m-%d %H:%M:%S", &res);
181 
182  tdsdump_log(TDS_DBG_INFO1, "Starting log file for FreeTDS %s\n"
183  "\ton %s with debug flags 0x%x.\n", VERSION, today, tds_debug_flags);
184  }
185  return result;
186 } /* tdsdump_open() */
187 
188 static FILE*
190 {
191  if (!g_dump_filename)
192  return NULL;
193 
194  if (!strcmp(g_dump_filename, "stdout")) {
195  return stdout;
196  } else if (!strcmp(g_dump_filename, "stderr")) {
197  return stderr;
198  }
199  return fopen(g_dump_filename, "a");
200 }
201 
202 
203 /**
204  * Close the TDS dump log file.
205  */
206 void
208 {
210  tds_write_dump = 0;
211  if (g_dumpfile != NULL && g_dumpfile != stdout && g_dumpfile != stderr)
212  fclose(g_dumpfile);
213  g_dumpfile = NULL;
214  if (g_dump_filename)
217 } /* tdsdump_close() */
218 
219 static void
220 tdsdump_start(FILE *file, const char *fname, int line)
221 {
222  char buf[128], *pbuf;
223  int started = 0;
224 
225  /* write always time before log */
227  fputs(tds_timestamp_str(buf, 127), file);
228  started = 1;
229  }
230 
231  pbuf = buf;
233  if (started)
234  *pbuf++ = ' ';
235  pbuf += sprintf(pbuf, "%d", (int) getpid());
236  started = 1;
237  }
238 
239  if ((tds_debug_flags & TDS_DBGFLAG_SOURCE) && fname && line) {
240  const char *p;
241  p = strrchr(fname, '/');
242  if (p)
243  fname = p + 1;
244  p = strrchr(fname, '\\');
245  if (p)
246  fname = p + 1;
247  if (started)
248  pbuf += sprintf(pbuf, " (%s:%d)", fname, line);
249  else
250  pbuf += sprintf(pbuf, "%s:%d", fname, line);
251  started = 1;
252  }
253  if (started)
254  *pbuf++ = ':';
255  *pbuf = 0;
256  fputs(buf, file);
257 }
258 
259 #undef tdsdump_dump_buf
260 /**
261  * Dump the contents of data into the log file in a human readable format.
262  * \param file source file name
263  * \param level_line line and level combined. This and file are automatically computed by
264  * TDS_DBG_* macros.
265  * \param msg message to print before dump
266  * \param buf buffer to dump
267  * \param length number of bytes in the buffer
268  */
269 void
270 tdsdump_do_dump_buf(const char* file, unsigned int level_line, const char *msg,
271  const void *buf, size_t length)
272 {
273  size_t i, j;
274 #define BYTES_PER_LINE 16
275  const unsigned char *data = (const unsigned char *) buf;
276  const int debug_lvl = level_line & 15;
277  const int line = level_line >> 4;
278  char line_buf[BYTES_PER_LINE * 8 + 16], *p;
279  FILE *dumpfile;
280 
281  if (((tds_debug_flags >> debug_lvl) & 1) == 0 || !tds_write_dump
282  || tdsdump_elided)
283  return;
284 
285  if (!g_dumpfile && !g_dump_filename)
286  return;
287 
289 
290  dumpfile = g_dumpfile;
291 #ifdef TDS_HAVE_MUTEX
292  if (tds_g_append_mode && dumpfile == NULL)
293  dumpfile = g_dumpfile = tdsdump_append();
294 #else
295  if (tds_g_append_mode)
296  dumpfile = tdsdump_append();
297 #endif
298 
299  if (dumpfile == NULL) {
301  return;
302  }
303 
304  tdsdump_start(dumpfile, file, line);
305 
306  fprintf(dumpfile, "%s\n", msg);
307 
308  for (i = 0; i < length; i += BYTES_PER_LINE) {
309  p = line_buf;
310  /*
311  * print the offset as a 4 digit hex number
312  */
313  p += sprintf(p, "%04x", ((unsigned int) i) & 0xffffu);
314 
315  /*
316  * print each byte in hex
317  */
318  for (j = 0; j < BYTES_PER_LINE; j++) {
319  if (j == BYTES_PER_LINE / 2)
320  *p++ = '-';
321  else
322  *p++ = ' ';
323  if (j + i >= length)
324  p += sprintf(p, " ");
325  else
326  p += sprintf(p, "%02x", data[i + j]);
327  }
328 
329  /*
330  * skip over to the ascii dump column
331  */
332  p += sprintf(p, " |");
333 
334  /*
335  * print each byte in ascii
336  */
337  for (j = i; j < length && (j - i) < BYTES_PER_LINE; j++) {
338  if (j - i == BYTES_PER_LINE / 2)
339  *p++ = ' ';
340  p += sprintf(p, "%c", (isprint(data[j])) ? data[j] : '.');
341  }
342  strcpy(p, "|\n");
343  fputs(line_buf, dumpfile);
344  }
345  fputs("\n", dumpfile);
346 
347  fflush(dumpfile);
348 
349 #ifndef TDS_HAVE_MUTEX
350  if (tds_g_append_mode) {
351  if (dumpfile != stdout && dumpfile != stderr)
352  fclose(dumpfile);
353  }
354 #endif
355 
357 
358 } /* tdsdump_dump_buf() */
359 #define tdsdump_dump_buf TDSDUMP_BUF_FAST
360 
361 
362 #undef tdsdump_log
363 /**
364  * Write a message to the debug log.
365  * \param file name of the log file
366  * \param level_line kind of detail to be included
367  * \param fmt printf-like format string
368  */
369 void
370 tdsdump_do_log(const char* file, unsigned int level_line, const char *fmt, ...)
371 {
372  const int debug_lvl = level_line & 15;
373  const int line = level_line >> 4;
374  va_list ap;
375  FILE *dumpfile;
376 
377  if (((tds_debug_flags >> debug_lvl) & 1) == 0 || !tds_write_dump)
378  return;
379 
380  if (!g_dumpfile && !g_dump_filename)
381  return;
382 
384 
385  dumpfile = g_dumpfile;
386 #ifdef TDS_HAVE_MUTEX
387  if (tds_g_append_mode && dumpfile == NULL)
388  dumpfile = g_dumpfile = tdsdump_append();
389 #else
390  if (tds_g_append_mode)
391  dumpfile = tdsdump_append();
392 #endif
393 
394  if (dumpfile == NULL) {
396  return;
397  }
398 
399  tdsdump_start(dumpfile, file, line);
400 
401  va_start(ap, fmt);
402 
403  vfprintf(dumpfile, fmt, ap);
404  va_end(ap);
405 
406  fflush(dumpfile);
407 
408 #ifndef TDS_HAVE_MUTEX
409  if (tds_g_append_mode) {
410  if (dumpfile != stdout && dumpfile != stderr)
411  fclose(dumpfile);
412  }
413 #endif
415 } /* tdsdump_log() */
416 #define tdsdump_log TDSDUMP_LOG_FAST
417 
418 
419 /**
420  * Write a column value to the debug log.
421  * \param col column to dump
422  */
423 void
425 {
426  const char* type_name;
427  char* data;
429 
430  assert(col);
431  assert(col->column_data);
432 
435 
436  switch(type) {
437  case SYBCHAR:
438  case SYBVARCHAR:
439  if (col->column_cur_size >= 0) {
440  data = tds_new0(char, 1 + col->column_cur_size);
441  if (!data) {
442  tdsdump_log(TDS_DBG_FUNC, "no memory to log data for type %s\n", type_name);
443  return;
444  }
445  memcpy(data, col->column_data, col->column_cur_size);
446  tdsdump_log(TDS_DBG_FUNC, "type %s has value \"%s\"\n", type_name, data);
447  free(data);
448  } else {
449  tdsdump_log(TDS_DBG_FUNC, "type %s has value NULL\n", type_name);
450  }
451  break;
452  case SYBINT1:
453  tdsdump_log(TDS_DBG_FUNC, "type %s has value %d\n", type_name, (int)*(TDS_TINYINT*)col->column_data);
454  break;
455  case SYBINT2:
456  tdsdump_log(TDS_DBG_FUNC, "type %s has value %d\n", type_name, (int)*(TDS_SMALLINT*)col->column_data);
457  break;
458  case SYBINT4:
459  tdsdump_log(TDS_DBG_FUNC, "type %s has value %d\n", type_name, (int)*(TDS_INT*)col->column_data);
460  break;
461  case SYBREAL:
462  tdsdump_log(TDS_DBG_FUNC, "type %s has value %f\n", type_name, (double)*(TDS_REAL*)col->column_data);
463  break;
464  case SYBFLT8:
465  tdsdump_log(TDS_DBG_FUNC, "type %s has value %f\n", type_name, (double)*(TDS_FLOAT*)col->column_data);
466  break;
467  default:
468  tdsdump_log(TDS_DBG_FUNC, "cannot log data for type %s\n", type_name);
469  break;
470  }
471 }
tds_sysdep_int32_type TDS_INT
Definition: tds.h:149
#define TDS_DBGFLAG_SOURCE
Definition: tds.h:918
#define TDS_DBG_INFO1
Definition: tds.h:900
tds_sysdep_real64_type TDS_FLOAT
Definition: tds.h:152
#define TDS_DBGFLAG_TIME
Definition: tds.h:917
tds_sysdep_real32_type TDS_REAL
Definition: tds.h:151
unsigned char TDS_TINYINT
Definition: tds.h:146
tds_sysdep_int16_type TDS_SMALLINT
Definition: tds.h:147
#define tds_new0(type, n)
Definition: tds.h:1393
#define TDS_DBGFLAG_ALL
Definition: tds.h:913
#define TDS_DBGFLAG_PID
Definition: tds.h:916
#define TDS_ZERO_FREE(x)
Definition: tds.h:359
#define TDS_DBG_FUNC
Definition: tds.h:898
#define tds_mutex_lock(x)
Definition: thread.h:421
#define tds_mutex_unlock(x)
Definition: thread.h:423
static int type
Definition: getdata.c:31
static char line_buf[1024]
Definition: parser.c:217
#define SYBINT4
Definition: sybdb.h:170
#define SYBVARCHAR
Definition: sybdb.h:162
#define SYBINT1
Definition: sybdb.h:166
#define SYBCHAR
Definition: sybdb.h:160
#define SYBREAL
Definition: sybdb.h:194
#define SYBFLT8
Definition: sybdb.h:174
#define SYBINT2
Definition: sybdb.h:168
static char * g_dump_filename
Definition: log.c:55
int tdsdump_elided
Definition: log.c:61
void tdsdump_on(void)
Turn logging back on.
Definition: log.c:93
int tds_g_append_mode
Definition: log.c:54
int tdsdump_open(const char *filename)
Create and truncate a human readable dump file for the TDS traffic.
Definition: log.c:126
#define tdsdump_log
Definition: log.c:416
void tdsdump_close(void)
Close the TDS dump log file.
Definition: log.c:207
void tdsdump_do_dump_buf(const char *file, unsigned int level_line, const char *msg, const void *buf, size_t length)
Dump the contents of data into the log file in a human readable format.
Definition: log.c:270
int tds_write_dump
Tell if TDS debug logging is turned on or off.
Definition: log.c:57
static FILE * tdsdump_append(void)
Definition: log.c:189
void tdsdump_do_log(const char *file, unsigned int level_line, const char *fmt,...)
Write a message to the debug log.
Definition: log.c:370
int tdsdump_isopen()
Definition: log.c:111
int tds_debug_flags
Definition: log.c:53
int tdsdump_state(void)
Get the logging state.
Definition: log.c:105
void tdsdump_col(const TDSCOLUMN *col)
Write a column value to the debug log.
Definition: log.c:424
#define BYTES_PER_LINE
static void tdsdump_start(FILE *file, const char *fname, int line)
Definition: log.c:220
void tdsdump_off(void)
Temporarily turn off logging.
Definition: log.c:81
static FILE * g_dumpfile
Definition: log.c:62
#define tds_timestamp_str
#define tds_localtime_r
#define tds_prtype
#define tds_get_conversion_type
#define TDS_MUTEX_INITIALIZER
Definition: thread.h:335
#define tds_mutex
Definition: thread.h:336
char data[12]
Definition: iconv.c:80
static tds_mutex g_dump_mutex
Definition: log.c:62
#define NULL
Definition: ncbistd.hpp:225
#define VERSION
Definition: config.h:13
FILE * file
char * buf
int i
void destructor(T1 *p)
Definition: tree_msvc7.hpp:72
int strcmp(const char *str1, const char *str2)
Definition: odbc_utils.hpp:160
#define strdup
Definition: ncbi_ansi_ext.h:70
EIPRangeType t
Definition: ncbi_localip.c:101
#define NCBI_TLS_VAR
Definition: ncbiconf_msvc.h:77
int isprint(Uchar c)
Definition: ncbictype.hpp:67
#define assert(x)
Definition: srv_diag.hpp:58
Metadata about columns in regular and compute rows.
Definition: tds.h:761
TDS_INT column_size
maximun size of data.
Definition: tds.h:766
TDS_SERVER_TYPE column_type
This type can be different from wire type because conversion (e.g.
Definition: tds.h:768
unsigned char * column_data
Definition: tds.h:793
TDS_INT column_cur_size
size written in variable (ie: char, text, binary).
Definition: tds.h:811
Definition: type.c:6
else result
Definition: token2.c:20
static const char * type_name(CS_INT value)
Definition: will_convert.c:122
void free(voidpf ptr)
Modified on Wed Jun 12 11:17:00 2024 by modify_doxy.py rev. 669887