Crow  0.0.4
crow_utilities.cpp
1 /*
2  _____ _____ _____ _ _ _
3 | | __ | | | | | Crow - a Sentry client for C++
4 | --| -| | | | | | version 0.0.4
5 |_____|__|__|_____|_____| https://github.com/nlohmann/crow
6 
7 Licensed under the MIT License <http://opensource.org/licenses/MIT>.
8 SPDX-License-Identifier: MIT
9 Copyright (c) 2018 Niels Lohmann <http://nlohmann.me>.
10 
11 Permission is hereby granted, free of charge, to any person obtaining a copy
12 of this software and associated documentation files (the "Software"), to deal
13 in the Software without restriction, including without limitation the rights
14 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 copies of the Software, and to permit persons to whom the Software is
16 furnished to do so, subject to the following conditions:
17 
18 The above copyright notice and this permission notice shall be included in all
19 copies or substantial portions of the Software.
20 
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 SOFTWARE.
28 */
29 
30 #include <chrono>
31 #include <typeinfo>
32 #include <src/crow_config.hpp>
33 #include <src/crow_utilities.hpp>
34 
35 #ifndef NLOHMANN_CROW_MINGW
36  #include <random>
37 #else
38  #include <cstdlib> // for srand, rand
39  #include <ctime> // for time
40 #endif
41 
42 #ifdef NLOHMANN_CROW_HAVE_CXXABI_H
43  #include <cxxabi.h> // for abi::__cxa_demangle
44 #endif
45 
46 #ifdef NLOHMANN_CROW_HAVE_EXECINFO_H
47  #include <execinfo.h> // for backtrace
48 #endif
49 
50 #ifdef NLOHMANN_CROW_HAVE_DLFCN_H
51  #include <dlfcn.h> // for dladdr
52 #endif
53 
54 namespace nlohmann
55 {
56 
57 namespace crow_utilities
58 {
59 
60 // https://gist.github.com/fmela/591333
61 // This function produces a stack backtrace with demangled function & method names.
62 json get_backtrace(int skip)
63 {
64  json result = json::array();
65 
66 #if defined(NLOHMANN_CROW_HAVE_DLFCN_H) && defined(NLOHMANN_CROW_HAVE_EXECINFO_H)
67  void* callstack[128];
68  const int nMaxFrames = sizeof(callstack) / sizeof(callstack[0]);
69  char buf[1024];
70  int nFrames = backtrace(callstack, nMaxFrames);
71  char** symbols = backtrace_symbols(callstack, nFrames);
72 
73  for (int i = skip; i < nFrames; i++)
74  {
75  Dl_info info;
76  if (dladdr(callstack[i], &info) && info.dli_sname)
77  {
78  char* demangled = nullptr;
79  int status = -1;
80  if (info.dli_sname[0] == '_')
81  {
82 #ifdef NLOHMANN_CROW_HAVE_CXXABI_H
83  demangled = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &status);
84 #endif
85  }
86 
87  const std::string function_name = (status == 0 ? demangled : info.dli_sname == nullptr ? symbols[i] : info.dli_sname);
88 
89  snprintf(buf, sizeof(buf), "%-3d %*p %s + %zd\n",
90  i, int(2 + sizeof(void*) * 2), callstack[i],
91  function_name.c_str(),
92  (char*) callstack[i] - (char*) info.dli_saddr);
93  //std::cout << buf << std::endl;
94 
95  json entry;
96  entry["function"] = function_name;
97 
98  if (not function_name.empty())
99  {
100  if (function_name.substr(0, 5) == "std::" or function_name.substr(0, 2) == "__")
101  {
102  entry["in_app"] = false;
103  }
104  }
105 
106  result.push_back(entry);
107 
108  free(demangled);
109  }
110  else
111  {
112  snprintf(buf, sizeof(buf), "%-3d %*p %s\n",
113  i, int(2 + sizeof(void*) * 2), callstack[i], symbols[i]);
114  }
115  }
116  free(symbols);
117 #endif
118 
119  return result;
120 }
121 
122 std::string pretty_name(const char* type_id_name,
123  const bool only_module)
124 {
125 #ifdef NLOHMANN_CROW_HAVE_CXXABI_H
126  int status;
127  std::string result = abi::__cxa_demangle(type_id_name, nullptr, nullptr, &status);
128 #else
129  std::string result = type_id_name;
130 #endif
131 
132  return only_module
133  ? result.substr(0, result.find_first_of(':'))
134  : result;
135 }
136 
137 std::int64_t get_timestamp()
138 {
139  const auto tp = std::chrono::system_clock::now();
140  const auto dur = tp.time_since_epoch();
141  return std::chrono::duration_cast<std::chrono::seconds>(dur).count();
142 }
143 
144 std::string get_iso8601()
145 {
146  std::time_t now;
147  std::time(&now);
148  char buf[sizeof "2011-10-08T07:07:09Z"];
149  std::strftime(buf, sizeof buf, "%Y-%m-%dT%H:%M:%SZ", std::gmtime(&now));
150  return buf;
151 }
152 
161 int get_random_number(int lower, int upper)
162 {
163 #ifdef NLOHMANN_CROW_MINGW
164  static bool init = false;
165  if (not init)
166  {
167  init = true;
168  std::srand(std::time(nullptr));
169  }
170  return std::rand() % upper + lower;
171 #else
172  static std::random_device random_device;
173  static std::default_random_engine random_engine(random_device());
174  static std::uniform_int_distribution<int> uniform_dist(lower, upper);
175  return uniform_dist(random_engine);
176 #endif
177 }
178 
179 std::string generate_uuid()
180 {
181  std::string result(32, ' ');
182 
183  for (std::size_t i = 0; i < result.size(); ++i)
184  {
185  // the 12th character must be a '4'
186  if (i == 12)
187  {
188  result[i] = '4';
189  }
190  else
191  {
192  // get a random number from 0..15
193  const auto r = static_cast<char>(get_random_number(0, 15));
194  if (r < 10)
195  {
196  result[i] = '0' + r;
197  }
198  else
199  {
200  result[i] = 'a' + r - static_cast<char>(10);
201  }
202  }
203  }
204 
205  return result;
206 }
207 
208 }
209 }
int get_random_number(int lower, int upper)
return a random integer
std::string get_iso8601()
get the current date and time as ISO 8601 string
json get_backtrace(int skip)
namespace for Niels Lohmann
Definition: crow.hpp:40
std::int64_t get_timestamp()
get the seconds since epoch
std::string pretty_name(const char *type_id_name, const bool only_module)
return pretty type name
std::string generate_uuid()
generate a UUID4 without dashes