1 /**
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 #if !defined(DLL_EXPORT) && !defined(USE_STATIC_LIB)
20 # define USE_STATIC_LIB
21 #endif
22
23 #include "zookeeper_log.h"
24 #ifndef WIN32
25 #include <unistd.h>
26 #else
27 typedef DWORD pid_t;
28 #include <process.h> /* for getpid */
29 #endif
30
31 #include <stdarg.h>
32 #include <time.h>
33
34 #define TIME_NOW_BUF_SIZE 1024
35 #define FORMAT_LOG_BUF_SIZE 4096
36
37 #ifdef THREADED
38 #ifndef WIN32
39 #include <pthread.h>
40 #else
41 #include "winport.h"
42 #endif
43
44 static pthread_key_t time_now_buffer;
45 static pthread_key_t format_log_msg_buffer;
46
freeBuffer(void * p)47 void freeBuffer(void* p){
48 if(p) free(p);
49 }
50
prepareTSDKeys()51 __attribute__((constructor)) void prepareTSDKeys() {
52 pthread_key_create (&time_now_buffer, freeBuffer);
53 pthread_key_create (&format_log_msg_buffer, freeBuffer);
54 }
55
getTSData(pthread_key_t key,int size)56 char* getTSData(pthread_key_t key,int size){
57 char* p=pthread_getspecific(key);
58 if(p==0){
59 int res;
60 p=calloc(1,size);
61 res=pthread_setspecific(key,p);
62 if(res!=0){
63 fprintf(stderr,"Failed to set TSD key: %d",res);
64 }
65 }
66 return p;
67 }
68
get_time_buffer()69 char* get_time_buffer(){
70 return getTSData(time_now_buffer,TIME_NOW_BUF_SIZE);
71 }
72
get_format_log_buffer()73 char* get_format_log_buffer(){
74 return getTSData(format_log_msg_buffer,FORMAT_LOG_BUF_SIZE);
75 }
76 #else
get_time_buffer()77 char* get_time_buffer(){
78 static char buf[TIME_NOW_BUF_SIZE];
79 return buf;
80 }
81
get_format_log_buffer()82 char* get_format_log_buffer(){
83 static char buf[FORMAT_LOG_BUF_SIZE];
84 return buf;
85 }
86
87 #endif
88
89 ZooLogLevel logLevel=ZOO_LOG_LEVEL_INFO;
90
91 static FILE* logStream=0;
zoo_get_log_stream()92 FILE* zoo_get_log_stream(){
93 if(logStream==0)
94 logStream=stderr;
95 return logStream;
96 }
97
zoo_set_log_stream(FILE * stream)98 void zoo_set_log_stream(FILE* stream){
99 logStream=stream;
100 }
101
time_now(char * now_str)102 static const char* time_now(char* now_str){
103 struct timeval tv;
104 struct tm lt;
105 time_t now = 0;
106 size_t len = 0;
107
108 gettimeofday(&tv,0);
109
110 now = tv.tv_sec;
111 localtime_r(&now, <);
112
113 // clone the format used by log4j ISO8601DateFormat
114 // specifically: "yyyy-MM-dd HH:mm:ss,SSS"
115
116 len = strftime(now_str, TIME_NOW_BUF_SIZE,
117 "%Y-%m-%d %H:%M:%S",
118 <);
119
120 len += snprintf(now_str + len,
121 TIME_NOW_BUF_SIZE - len,
122 ",%03d",
123 (int)(tv.tv_usec/1000));
124
125 return now_str;
126 }
127
log_message(log_callback_fn callback,ZooLogLevel curLevel,int line,const char * funcName,const char * format,...)128 void log_message(log_callback_fn callback, ZooLogLevel curLevel,
129 int line, const char* funcName, const char* format, ...)
130 {
131 static const char* dbgLevelStr[]={"ZOO_INVALID","ZOO_ERROR","ZOO_WARN",
132 "ZOO_INFO","ZOO_DEBUG"};
133 static pid_t pid=0;
134 va_list va;
135 int ofs = 0;
136 #ifdef THREADED
137 unsigned long int tid = 0;
138 #endif
139 #ifdef WIN32
140 char timebuf [TIME_NOW_BUF_SIZE];
141 const char* time = time_now(timebuf);
142 #else
143 const char* time = time_now(get_time_buffer());
144 #endif
145
146 char* buf = get_format_log_buffer();
147 if(!buf)
148 {
149 fprintf(stderr, "log_message: Unable to allocate memory buffer");
150 return;
151 }
152
153 if(pid==0)
154 {
155 pid=getpid();
156 }
157
158
159 #ifndef THREADED
160
161 // pid_t is long on Solaris
162 ofs = snprintf(buf, FORMAT_LOG_BUF_SIZE,
163 "%s:%ld:%s@%s@%d: ", time, (long)pid,
164 dbgLevelStr[curLevel], funcName, line);
165 #else
166
167 #ifdef WIN32
168 tid = (unsigned long int)(pthread_self().thread_id);
169 #else
170 tid = (unsigned long int)(pthread_self());
171 #endif
172
173 ofs = snprintf(buf, FORMAT_LOG_BUF_SIZE-1,
174 "%s:%ld(0x%lx):%s@%s@%d: ", time, (long)pid, tid,
175 dbgLevelStr[curLevel], funcName, line);
176 #endif
177
178 // Now grab the actual message out of the variadic arg list
179 va_start(va, format);
180 vsnprintf(buf+ofs, FORMAT_LOG_BUF_SIZE-1-ofs, format, va);
181 va_end(va);
182
183 if (callback)
184 {
185 callback(buf);
186 } else {
187 fprintf(zoo_get_log_stream(), "%s\n", buf);
188 fflush(zoo_get_log_stream());
189 }
190 }
191
zoo_set_debug_level(ZooLogLevel level)192 void zoo_set_debug_level(ZooLogLevel level)
193 {
194 if(level==0){
195 // disable logging (unit tests do this)
196 logLevel=(ZooLogLevel)0;
197 return;
198 }
199 if(level<ZOO_LOG_LEVEL_ERROR)level=ZOO_LOG_LEVEL_ERROR;
200 if(level>ZOO_LOG_LEVEL_DEBUG)level=ZOO_LOG_LEVEL_DEBUG;
201 logLevel=level;
202 }
203
204