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 #include <cstring> 38 39 using namespace std; 40 41 /** 42 * Tracking for the stacks 43 */ 44 vector<vector<Trace *> > Trace::stacks; 45 46 /** 47 * The indentation string for output 48 */ 49 vector<string> Trace::indent; 50 51 #define MAX_MSG_PREFIX_LEN 128 52 #define CTIME_LEN 26 53 #define DEBUG_FILE "/var/adm/sun_fc.debug" 54 #define LOG_FILE "/var/adm/sun_fc" 55 56 /** 57 * @memo Log a message 58 * @param priority The priority of the message (see syslog man page) 59 * @param msg The message string 60 * 61 * @doc If the debug file is present, we will log everything to 62 * that file. Otherwise, if the normal log file is present, 63 * we'll log all non-debug messages to that file. Lastly, 64 * if neither file is present, the message will be 65 * silently discarded. 66 */ 67 void Trace::message(int priority, const char *msg) { 68 char prefix[MAX_MSG_PREFIX_LEN]; 69 char message[MAX_MSG_PREFIX_LEN + MAX_MSG_LEN + 2]; 70 int fd; 71 // char time[CTIME_LEN+1]; 72 std::string priString; 73 74 75 /* If we can open the log file, write there, else use the cim log */ 76 fd = open(DEBUG_FILE, O_WRONLY|O_APPEND); /* will only open if exists */ 77 if (fd == -1) { 78 /* No debug file, how about the log file? */ 79 if (priority == LOG_DEBUG) { 80 return; /* Ignore debug */ 81 } 82 fd = open(LOG_FILE, O_WRONLY|O_APPEND); 83 /* We catch open failures later */ 84 } 85 86 // now(time); 87 /* First interpret the priority value */ 88 switch (priority) { 89 case INTERNAL_ERROR: 90 priString = "INTERNAL"; 91 break; 92 case STACK_TRACE: 93 priString = "STACK"; 94 break; 95 case IO_ERROR: 96 priString = "IO"; 97 break; 98 case USER_ERROR: 99 priString = "USER"; 100 break; 101 case LOG_DEBUG: 102 priString = "DEBUG"; 103 break; 104 default: 105 priString = "UNKNOWN"; 106 break; 107 } 108 109 if (fd != -1) { 110 /* Format the prefix string for the log file */ 111 snprintf(prefix, MAX_MSG_PREFIX_LEN, "%d:%d:%s%s:%s", 112 time(NULL), 113 tid, 114 indent[tid].c_str(), 115 routine.c_str(), 116 priString.c_str()); 117 118 /* Format the message string for the log file */ 119 snprintf(message, strlen(prefix) + MAX_MSG_LEN + 2, "%s:%s\n", 120 prefix, 121 msg); 122 write(fd, message, strlen(message)); 123 close(fd); 124 } /* Else discard the log message */ 125 } 126 127 /** 128 * @memo Create a new Trace instance and update stack. 129 * @param myRoutine The name of the routine 130 * 131 * @doc This class was developed to provide a Java 132 * like stack trace capability, as C++ does not provide 133 * a run-time stack lookup feature. Instances of the 134 * Trace class should be created on the stack so they 135 * will be automatically freed when the stack is popped 136 * when the function returns. 137 */ 138 Trace::Trace(std::string myRoutine) : routine(myRoutine) { 139 tid = pthread_self(); 140 if (stacks.size() < tid+1) { 141 stacks.resize(tid+1); 142 indent.resize(tid+1); 143 indent[tid] = ""; 144 } 145 message(LOG_DEBUG, "entered"); 146 stacks[tid].push_back(this); 147 indent[tid] += " "; 148 } 149 150 /** 151 * @memo Delete a trace instances and update the stack 152 */ 153 Trace::~Trace() { 154 string::size_type len = indent[tid].size(); 155 if (len > 0) { 156 indent[tid].resize(len - 1); 157 } 158 message(LOG_DEBUG, "exited"); 159 stacks[tid].pop_back(); 160 } 161 162 /** 163 * @memo Print out the current stack trace information 164 */ 165 void Trace::stackTrace() { 166 message(STACK_TRACE, "Stack trace follows"); 167 for (vector<Trace *>::size_type i = stacks[tid].size() - 1; ; i--) { 168 string msg = " "; 169 msg += (stacks[tid])[i]->label(); 170 message(STACK_TRACE, msg.c_str()); 171 if (i == 0) { 172 break; 173 } 174 } 175 } 176