1 /* 2 * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include "util.h" 27 28 #include <time.h> 29 #include <errno.h> 30 #include <sys/types.h> 31 32 #include "proc_md.h" 33 34 #include "log_messages.h" 35 36 #ifdef JDWP_LOGGING 37 38 #define MAXLEN_INTEGER 20 39 #define MAXLEN_FILENAME 256 40 #define MAXLEN_TIMESTAMP 80 41 #define MAXLEN_LOCATION (MAXLEN_FILENAME+MAXLEN_INTEGER+16) 42 #define MAXLEN_MESSAGE 256 43 #define MAXLEN_EXEC (MAXLEN_FILENAME*2+MAXLEN_INTEGER+16) 44 45 static MUTEX_T my_mutex = MUTEX_INIT; 46 47 /* Static variables (should be protected with mutex) */ 48 static int logging; 49 static FILE * log_file; 50 static char logging_filename[MAXLEN_FILENAME+1+6]; 51 static char location_stamp[MAXLEN_LOCATION+1]; 52 static PID_T processPid; 53 static int open_count; 54 55 /* Ascii id of current native thread. */ 56 static void 57 get_time_stamp(char *tbuf, size_t ltbuf) 58 { 59 char timestamp_prefix[MAXLEN_TIMESTAMP+1]; 60 char timestamp_postfix[MAXLEN_TIMESTAMP+1]; 61 unsigned millisecs = 0; 62 time_t t = 0; 63 64 GETMILLSECS(millisecs); 65 if ( time(&t) == (time_t)(-1) ) 66 t = 0; 67 (void)strftime(timestamp_prefix, sizeof(timestamp_prefix), 68 /* Break this string up for SCCS's sake */ 69 "%" "d.%" "m.%" "Y %" "T", localtime(&t)); 70 (void)strftime(timestamp_postfix, sizeof(timestamp_postfix), 71 /* Break this string up for SCCS's sake */ 72 "%" "Z", localtime(&t)); 73 (void)snprintf(tbuf, ltbuf, "%s.%.3d %s", timestamp_prefix, (int)(millisecs), timestamp_postfix); 74 } 75 76 /* Get basename of filename */ 77 static const char * 78 file_basename(const char *file) 79 { 80 char *p1; 81 char *p2; 82 83 if ( file==NULL ) 84 return "unknown"; 85 p1 = strrchr(file, '\\'); 86 p2 = strrchr(file, '/'); 87 p1 = ((p1 > p2) ? p1 : p2); 88 if (p1 != NULL) { 89 file = p1 + 1; 90 } 91 return file; 92 } 93 94 /* Fill in the exact source location of the LOG entry. */ 95 static void 96 fill_location_stamp(const char *flavor, const char *file, int line) 97 { 98 (void)snprintf(location_stamp, sizeof(location_stamp), 99 "%s:\"%s\":%d;", 100 flavor, file_basename(file), line); 101 location_stamp[sizeof(location_stamp)-1] = 0; 102 } 103 104 /* Begin a log entry. */ 105 void 106 log_message_begin(const char *flavor, const char *file, int line) 107 { 108 MUTEX_LOCK(my_mutex); /* Unlocked in log_message_end() */ 109 if ( logging ) { 110 location_stamp[0] = 0; 111 fill_location_stamp(flavor, file, line); 112 } 113 } 114 115 /* Standard Logging Format Entry */ 116 static void 117 standard_logging_format(FILE *fp, 118 const char *datetime, 119 const char *level, 120 const char *product, 121 const char *module, 122 const char *optional, 123 const char *messageID, 124 const char *message) 125 { 126 const char *format; 127 128 /* "[#|Date&Time&Zone|LogLevel|ProductName|ModuleID| 129 * OptionalKey1=Value1;OptionalKeyN=ValueN|MessageID:MessageText|#]\n" 130 */ 131 132 format="[#|%s|%s|%s|%s|%s|%s:%s|#]\n"; 133 134 print_message(fp, "", "", format, 135 datetime, 136 level, 137 product, 138 module, 139 optional, 140 messageID, 141 message); 142 } 143 144 /* End a log entry */ 145 void 146 log_message_end(const char *format, ...) 147 { 148 if ( logging ) { 149 va_list ap; 150 THREAD_T tid; 151 char datetime[MAXLEN_TIMESTAMP+1]; 152 const char *level; 153 const char *product; 154 const char *module; 155 char optional[MAXLEN_INTEGER+6+MAXLEN_INTEGER+6+MAXLEN_LOCATION+1]; 156 const char *messageID; 157 char message[MAXLEN_MESSAGE+1]; 158 159 /* Grab the location, start file if needed, and clear the lock */ 160 if ( log_file == NULL && open_count == 0 && logging_filename[0] != 0 ) { 161 open_count++; 162 log_file = fopen(logging_filename, "w"); 163 if ( log_file!=NULL ) { 164 (void)setvbuf(log_file, NULL, _IOLBF, BUFSIZ); 165 } else { 166 logging = 0; 167 } 168 } 169 170 if ( log_file != NULL ) { 171 172 /* Get the rest of the needed information */ 173 tid = GET_THREAD_ID(); 174 level = "FINEST"; /* FIXUP? */ 175 product = "J2SE1.5"; /* FIXUP? */ 176 module = "jdwp"; /* FIXUP? */ 177 messageID = ""; /* FIXUP: Unique message string ID? */ 178 (void)snprintf(optional, sizeof(optional), 179 "LOC=%s;PID=%d;THR=t@%d", 180 location_stamp, 181 (int)processPid, 182 (int)(intptr_t)tid); 183 184 /* Construct message string. */ 185 va_start(ap, format); 186 (void)vsnprintf(message, sizeof(message), format, ap); 187 va_end(ap); 188 189 get_time_stamp(datetime, sizeof(datetime)); 190 191 /* Send out standard logging format message */ 192 standard_logging_format(log_file, 193 datetime, 194 level, 195 product, 196 module, 197 optional, 198 messageID, 199 message); 200 } 201 location_stamp[0] = 0; 202 } 203 MUTEX_UNLOCK(my_mutex); /* Locked in log_message_begin() */ 204 } 205 206 #endif 207 208 /* Set up the logging with the name of a logging file. */ 209 void 210 setup_logging(const char *filename, unsigned flags) 211 { 212 #ifdef JDWP_LOGGING 213 FILE *fp = NULL; 214 215 /* Turn off logging */ 216 logging = 0; 217 gdata->log_flags = 0; 218 219 /* Just return if not doing logging */ 220 if ( filename==NULL || flags==0 ) 221 return; 222 223 /* Create potential filename for logging */ 224 processPid = GETPID(); 225 (void)snprintf(logging_filename, sizeof(logging_filename), 226 "%s.%d", filename, (int)processPid); 227 228 /* Turn on logging (do this last) */ 229 logging = 1; 230 gdata->log_flags = flags; 231 232 #endif 233 } 234 235 /* Finish up logging, flush output to the logfile. */ 236 void 237 finish_logging(int exit_code) 238 { 239 #ifdef JDWP_LOGGING 240 MUTEX_LOCK(my_mutex); 241 if ( logging ) { 242 logging = 0; 243 if ( log_file != NULL ) { 244 (void)fflush(log_file); 245 (void)fclose(log_file); 246 log_file = NULL; 247 } 248 } 249 MUTEX_UNLOCK(my_mutex); 250 #endif 251 }