Panda3D
notifyCategory.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file notifyCategory.cxx
10  * @author drose
11  * @date 2000-02-29
12  */
13 
14 #include "notifyCategory.h"
15 #include "pnotify.h"
16 #include "configPageManager.h"
17 #include "configVariableString.h"
18 #include "configVariableBool.h"
19 #include "config_prc.h"
20 
21 #ifdef ANDROID
22 #include "androidLogStream.h"
23 #endif
24 
25 #include <time.h> // for strftime().
26 #include <assert.h>
27 
28 long NotifyCategory::_server_delta = 0;
29 
30 /**
31  *
32  */
33 NotifyCategory::
34 NotifyCategory(const std::string &fullname, const std::string &basename,
35  NotifyCategory *parent) :
36  _fullname(fullname),
37  _basename(basename),
38  _parent(parent),
39  _severity(get_config_name(), NS_unspecified,
40  "Default severity of this notify category",
41  ConfigVariable::F_dynamic),
42  _local_modified(initial_invalid_cache())
43 {
44  if (_parent != nullptr) {
45  _parent->_children.push_back(this);
46  }
47 
48  // Only the unnamed top category is allowed not to have a parent.
49  nassertv(_parent != nullptr || _fullname.empty());
50 }
51 
52 /**
53  * Begins a new message to this Category at the indicated severity level. If
54  * the indicated severity level is enabled, this writes a prefixing string to
55  * the Notify::out() stream and returns that. If the severity level is
56  * disabled, this returns Notify::null().
57  */
58 std::ostream &NotifyCategory::
59 out(NotifySeverity severity, bool prefix) const {
60  if (is_on(severity)) {
61 
62 #ifdef ANDROID
63  // Android redirects stdio and stderr to devnull, but does provide its own
64  // logging system. We use a special type of stream that redirects it to
65  // Android's log system.
66  if (prefix) {
67  if (severity == NS_info) {
68  return AndroidLogStream::out(severity) << *this << ": ";
69  } else {
70  return AndroidLogStream::out(severity) << *this << "(" << severity << "): ";
71  }
72  } else {
73  return AndroidLogStream::out(severity);
74  }
75 #else
76 
77  if (prefix) {
78  if (get_notify_timestamp()) {
79  // Format a timestamp to include as a prefix as well.
80  time_t now = time(nullptr) + _server_delta;
81  struct tm atm;
82 #ifdef _WIN32
83  localtime_s(&atm, &now);
84 #else
85  localtime_r(&now, &atm);
86 #endif
87 
88  char buffer[128];
89  strftime(buffer, 128, ":%m-%d-%Y %H:%M:%S ", &atm);
90  nout << buffer;
91  }
92 
93  if (severity == NS_info) {
94  return nout << *this << ": ";
95  } else {
96  return nout << *this << "(" << severity << "): ";
97  }
98  } else {
99  return nout;
100  }
101 #endif
102 
103  } else if (severity <= NS_debug && get_check_debug_notify_protect()) {
104  // Someone issued a debug Notify output statement without protecting it
105  // within an if statement. This can cause a significant runtime
106  // performance hit, since it forces the iostream library to fully format
107  // its output, and then discards the output.
108  nout << " **Not protected!** ";
109  if (prefix) {
110  nout << *this << "(" << severity << "): ";
111  }
112  if (assert_abort) {
113  nassert_raise("unprotected debug statement");
114  }
115 
116  return nout;
117 
118  } else {
119  return Notify::null();
120  }
121 }
122 
123 /**
124  * Returns the number of child Categories of this particular Category.
125  */
126 size_t NotifyCategory::
127 get_num_children() const {
128  return _children.size();
129 }
130 
131 /**
132  * Returns the nth child Category of this particular Category.
133  */
135 get_child(size_t i) const {
136  assert(i < _children.size());
137  return _children[i];
138 }
139 
140 /**
141  * Sets a global delta (in seconds) between the local time and the server's
142  * time, for the purpose of synchronizing the time stamps in the log messages
143  * of the client with that of a known server.
144  */
145 void NotifyCategory::
146 set_server_delta(long delta) {
147  _server_delta = delta;
148 }
149 
150 /**
151  * Returns the name of the config variable that controls this category. This
152  * is called at construction time.
153  */
154 std::string NotifyCategory::
155 get_config_name() const {
156  std::string config_name;
157 
158  if (_fullname.empty()) {
159  config_name = "notify-level";
160  } else if (!_basename.empty()) {
161  config_name = "notify-level-" + _basename;
162  }
163 
164  return config_name;
165 }
166 
167 /**
168  *
169  */
170 void NotifyCategory::
171 update_severity_cache() {
172  if (_severity == NS_unspecified) {
173  // If we don't have an explicit severity level, inherit our parent's.
174  if (_severity.has_value()) {
175  nout << "Invalid severity name for " << _severity.get_name() << ": "
176  << _severity.get_string_value() << "\n";
177  }
178  if (_parent != nullptr) {
179  _severity_cache = _parent->get_severity();
180 
181  } else {
182  // Unless, of course, we're the root.
183  _severity_cache = NS_info;
184  }
185  } else {
186  _severity_cache = _severity;
187  }
188  mark_cache_valid(_local_modified);
189 }
190 
191 /**
192  * Returns the value of the notify-timestamp ConfigVariable. This is defined
193  * using a method accessor rather than a static ConfigVariableBool, to protect
194  * against the variable needing to be accessed at static init time.
195  */
196 bool NotifyCategory::
197 get_notify_timestamp() {
198  static ConfigVariableBool *notify_timestamp = nullptr;
199  if (notify_timestamp == nullptr) {
200  notify_timestamp = new ConfigVariableBool
201  ("notify-timestamp", false,
202  "Set true to output the date & time with each notify message.");
203  }
204  return *notify_timestamp;
205 }
206 
207 /**
208  * Returns the value of the check-debug-notify-protect ConfigVariable. This
209  * is defined using a method accessor rather than a static ConfigVariableBool,
210  * to protect against the variable needing to be accessed at static init time.
211  */
212 bool NotifyCategory::
213 get_check_debug_notify_protect() {
214  static ConfigVariableBool *check_debug_notify_protect = nullptr;
215  if (check_debug_notify_protect == nullptr) {
216  check_debug_notify_protect = new ConfigVariableBool
217  ("check-debug-notify-protect", false,
218  "Set true to issue a warning message if a debug or spam "
219  "notify output is not protected within an if statement.");
220  }
221  return *check_debug_notify_protect;
222 }
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is a convenience class to specialize ConfigVariable as a boolean type.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A particular category of error messages.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static std::ostream & null()
A convenient way to get an ostream that doesn't do anything.
Definition: notify.cxx:270
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is a generic, untyped ConfigVariable.
const std::string & get_string_value() const
Returns the toplevel value of the variable, formatted as a string.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_child
Returns the nth child Category of this particular Category.
static void set_server_delta(long delta)
Sets a global delta (in seconds) between the local time and the server's time, for the purpose of syn...
get_name
Returns the name of the variable.
bool has_value() const
Returns true if this variable has an explicit value, either from a prc file or locally set,...
bool is_on(NotifySeverity severity) const
Returns true if messages of the indicated severity level ought to be reported for this Category.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
std::ostream & out(NotifySeverity severity, bool prefix=true) const
Begins a new message to this Category at the indicated severity level.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.