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