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 */
message(int priority,const char * msg)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 */
Trace(std::string myRoutine)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 */
~Trace()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 */
stackTrace()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