1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 27 28 #include "Trace.h" 29 #include <cstdarg> 30 #include <string> 31 #include <cstdio> 32 #include <string> 33 #include <sys/types.h> 34 #include <sys/stat.h> 35 #include <fcntl.h> 36 #include <unistd.h> 37 38 using namespace std; 39 40 /** 41 * Tracking for the stacks 42 */ 43 vector<vector<Trace *> > Trace::stacks; 44 45 /** 46 * The indentation string for output 47 */ 48 vector<string> Trace::indent; 49 50 #define MAX_MSG_PREFIX_LEN 128 51 #define CTIME_LEN 26 52 #define DEBUG_FILE "/var/adm/sun_fc.debug" 53 #define LOG_FILE "/var/adm/sun_fc" 54 55 /** 56 * @memo Log a message 57 * @param priority The priority of the message (see syslog man page) 58 * @param msg The message string 59 * 60 * @doc If the debug file is present, we will log everything to 61 * that file. Otherwise, if the normal log file is present, 62 * we'll log all non-debug messages to that file. Lastly, 63 * if neither file is present, the message will be 64 * silently discarded. 65 */ 66 void Trace::message(int priority, const char *msg) { 67 char prefix[MAX_MSG_PREFIX_LEN]; 68 char message[MAX_MSG_PREFIX_LEN + MAX_MSG_LEN + 2]; 69 int fd; 70 // char time[CTIME_LEN+1]; 71 std::string priString; 72 73 74 /* If we can open the log file, write there, else use the cim log */ 75 fd = open(DEBUG_FILE, O_WRONLY|O_APPEND); /* will only open if exists */ 76 if (fd == -1) { 77 /* No debug file, how about the log file? */ 78 if (priority == LOG_DEBUG) { 79 return; /* Ignore debug */ 80 } 81 fd = open(LOG_FILE, O_WRONLY|O_APPEND); 82 /* We catch open failures later */ 83 } 84 85 // now(time); 86 /* First interpret the priority value */ 87 switch (priority) { 88 case INTERNAL_ERROR: 89 priString = "INTERNAL"; 90 break; 91 case STACK_TRACE: 92 priString = "STACK"; 93 break; 94 case IO_ERROR: 95 priString = "IO"; 96 break; 97 case USER_ERROR: 98 priString = "USER"; 99 break; 100 case LOG_DEBUG: 101 priString = "DEBUG"; 102 break; 103 default: 104 priString = "UNKNOWN"; 105 break; 106 } 107 108 if (fd != -1) { 109 /* Format the prefix string for the log file */ 110 snprintf(prefix, MAX_MSG_PREFIX_LEN, "%d:%d:%s%s:%s", 111 time(NULL), 112 tid, 113 indent[tid].c_str(), 114 routine.c_str(), 115 priString.c_str()); 116 117 /* Format the message string for the log file */ 118 snprintf(message, strlen(prefix) + MAX_MSG_LEN + 2, "%s:%s\n", 119 prefix, 120 msg); 121 write(fd, message, strlen(message)); 122 close(fd); 123 } /* Else discard the log message */ 124 } 125 126 /** 127 * @memo Create a new Trace instance and update stack. 128 * @param myRoutine The name of the routine 129 * 130 * @doc This class was developed to provide a Java 131 * like stack trace capability, as C++ does not provide 132 * a run-time stack lookup feature. Instances of the 133 * Trace class should be created on the stack so they 134 * will be automatically freed when the stack is popped 135 * when the function returns. 136 */ 137 Trace::Trace(std::string myRoutine) : routine(myRoutine) { 138 tid = pthread_self(); 139 if (stacks.size() < tid+1) { 140 stacks.resize(tid+1); 141 indent.resize(tid+1); 142 indent[tid] = ""; 143 } 144 message(LOG_DEBUG, "entered"); 145 stacks[tid].push_back(this); 146 indent[tid] += " "; 147 } 148 149 /** 150 * @memo Delete a trace instances and update the stack 151 */ 152 Trace::~Trace() { 153 string::size_type len = indent[tid].size(); 154 if (len > 0) { 155 indent[tid].resize(len - 1); 156 } 157 message(LOG_DEBUG, "exited"); 158 stacks[tid].pop_back(); 159 } 160 161 /** 162 * @memo Print out the current stack trace information 163 */ 164 void Trace::stackTrace() { 165 message(STACK_TRACE, "Stack trace follows"); 166 for (vector<Trace *>::size_type i = stacks[tid].size() - 1; ; i--) { 167 string msg = " "; 168 msg += (stacks[tid])[i]->label(); 169 message(STACK_TRACE, msg.c_str()); 170 if (i == 0) { 171 break; 172 } 173 } 174 } 175