xref: /illumos-gate/usr/src/lib/sun_fc/common/Trace.cc (revision 69a119caa6570c7077699161b7c28b6ee9f8b0f4)
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