xref: /illumos-gate/usr/src/lib/sun_fc/common/Trace.cc (revision f3aaec0a)
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  */
message(int priority,const char * msg)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  */
Trace(std::string myRoutine)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  */
~Trace()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  */
stackTrace()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 }