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