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