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 45static MUTEX_T my_mutex = MUTEX_INIT; 46 47/* Static variables (should be protected with mutex) */ 48static int logging; 49static FILE * log_file; 50static char logging_filename[MAXLEN_FILENAME+1+6]; 51static char location_stamp[MAXLEN_LOCATION+1]; 52static PID_T processPid; 53static int open_count; 54 55/* Ascii id of current native thread. */ 56static void 57get_time_stamp(char *tbuf, size_t ltbuf) 58{ 59 char format[MAXLEN_TIMESTAMP+1]; 60 unsigned millisecs = 0; 61 time_t t = 0; 62 63 GETMILLSECS(millisecs); 64 if ( time(&t) == (time_t)(-1) ) 65 t = 0; 66 (void)strftime(format, sizeof(format), 67 /* Break this string up for SCCS's sake */ 68 "%" "d.%" "m.%" "Y %" "T.%%.3d %" "Z", localtime(&t)); 69 (void)snprintf(tbuf, ltbuf, format, (int)(millisecs)); 70} 71 72/* Get basename of filename */ 73static const char * 74file_basename(const char *file) 75{ 76 char *p1; 77 char *p2; 78 79 if ( file==NULL ) 80 return "unknown"; 81 p1 = strrchr(file, '\\'); 82 p2 = strrchr(file, '/'); 83 p1 = ((p1 > p2) ? p1 : p2); 84 if (p1 != NULL) { 85 file = p1 + 1; 86 } 87 return file; 88} 89 90/* Fill in the exact source location of the LOG entry. */ 91static void 92fill_location_stamp(const char *flavor, const char *file, int line) 93{ 94 (void)snprintf(location_stamp, sizeof(location_stamp), 95 "%s:\"%s\":%d;", 96 flavor, file_basename(file), line); 97 location_stamp[sizeof(location_stamp)-1] = 0; 98} 99 100/* Begin a log entry. */ 101void 102log_message_begin(const char *flavor, const char *file, int line) 103{ 104 MUTEX_LOCK(my_mutex); /* Unlocked in log_message_end() */ 105 if ( logging ) { 106 location_stamp[0] = 0; 107 fill_location_stamp(flavor, file, line); 108 } 109} 110 111/* Standard Logging Format Entry */ 112static void 113standard_logging_format(FILE *fp, 114 const char *datetime, 115 const char *level, 116 const char *product, 117 const char *module, 118 const char *optional, 119 const char *messageID, 120 const char *message) 121{ 122 const char *format; 123 124 /* "[#|Date&Time&Zone|LogLevel|ProductName|ModuleID| 125 * OptionalKey1=Value1;OptionalKeyN=ValueN|MessageID:MessageText|#]\n" 126 */ 127 128 format="[#|%s|%s|%s|%s|%s|%s:%s|#]\n"; 129 130 print_message(fp, "", "", format, 131 datetime, 132 level, 133 product, 134 module, 135 optional, 136 messageID, 137 message); 138} 139 140/* End a log entry */ 141void 142log_message_end(const char *format, ...) 143{ 144 if ( logging ) { 145 va_list ap; 146 THREAD_T tid; 147 char datetime[MAXLEN_TIMESTAMP+1]; 148 const char *level; 149 const char *product; 150 const char *module; 151 char optional[MAXLEN_INTEGER+6+MAXLEN_INTEGER+6+MAXLEN_LOCATION+1]; 152 const char *messageID; 153 char message[MAXLEN_MESSAGE+1]; 154 155 /* Grab the location, start file if needed, and clear the lock */ 156 if ( log_file == NULL && open_count == 0 && logging_filename[0] != 0 ) { 157 open_count++; 158 log_file = fopen(logging_filename, "w"); 159 if ( log_file!=NULL ) { 160 (void)setvbuf(log_file, NULL, _IOLBF, BUFSIZ); 161 } else { 162 logging = 0; 163 } 164 } 165 166 if ( log_file != NULL ) { 167 168 /* Get the rest of the needed information */ 169 tid = GET_THREAD_ID(); 170 level = "FINEST"; /* FIXUP? */ 171 product = "J2SE1.5"; /* FIXUP? */ 172 module = "jdwp"; /* FIXUP? */ 173 messageID = ""; /* FIXUP: Unique message string ID? */ 174 (void)snprintf(optional, sizeof(optional), 175 "LOC=%s;PID=%d;THR=t@%d", 176 location_stamp, 177 (int)processPid, 178 (int)tid); 179 180 /* Construct message string. */ 181 va_start(ap, format); 182 (void)vsnprintf(message, sizeof(message), format, ap); 183 va_end(ap); 184 185 get_time_stamp(datetime, sizeof(datetime)); 186 187 /* Send out standard logging format message */ 188 standard_logging_format(log_file, 189 datetime, 190 level, 191 product, 192 module, 193 optional, 194 messageID, 195 message); 196 } 197 location_stamp[0] = 0; 198 } 199 MUTEX_UNLOCK(my_mutex); /* Locked in log_message_begin() */ 200} 201 202#endif 203 204/* Set up the logging with the name of a logging file. */ 205void 206setup_logging(const char *filename, unsigned flags) 207{ 208#ifdef JDWP_LOGGING 209 FILE *fp = NULL; 210 211 /* Turn off logging */ 212 logging = 0; 213 gdata->log_flags = 0; 214 215 /* Just return if not doing logging */ 216 if ( filename==NULL || flags==0 ) 217 return; 218 219 /* Create potential filename for logging */ 220 processPid = GETPID(); 221 (void)snprintf(logging_filename, sizeof(logging_filename), 222 "%s.%d", filename, (int)processPid); 223 224 /* Turn on logging (do this last) */ 225 logging = 1; 226 gdata->log_flags = flags; 227 228#endif 229} 230 231/* Finish up logging, flush output to the logfile. */ 232void 233finish_logging() 234{ 235#ifdef JDWP_LOGGING 236 MUTEX_LOCK(my_mutex); 237 if ( logging ) { 238 logging = 0; 239 if ( log_file != NULL ) { 240 (void)fflush(log_file); 241 (void)fclose(log_file); 242 log_file = NULL; 243 } 244 } 245 MUTEX_UNLOCK(my_mutex); 246#endif 247} 248