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