Repo-Init
 
Loading...
Searching...
No Matches
Sentry.cpp
Go to the documentation of this file.
1#include "logging/Sentry.hpp"
2
3#include "Version.h"
5
6#include <array>
7#include <format>
8
9#include <arpa/inet.h>
10#include <ifaddrs.h>
11#include <net/if.h>
12#include <netpacket/packet.h>
13#include <unistd.h>
14
15#include <sentry.h>
16#include <spdlog/spdlog.h>
17
18// MAC address length for character string
19constexpr int MAC_LEN = 18;
20
21namespace
22{
24 void setVersionContext()
25 {
26 std::string versionBuffer;
27 const sentry_value_t versionContext = sentry_value_new_object();
28 versionBuffer = "v" + std::string(PROJECT_FULL_REVISION);
29 sentry_value_set_by_key(versionContext, PROJECT_NAME, sentry_value_new_string(versionBuffer.c_str()));
30 versionBuffer = std::string(PROJECT_BUILD_DATE) + " " + PROJECT_BUILD_TIME;
31 sentry_value_set_by_key(versionContext, "Release Date", sentry_value_new_string(versionBuffer.c_str()));
32 sentry_set_context("Version", versionContext);
33 }
34
36 void setHostContext()
37 {
38 std::array<char, BUFSIZ> hostBuffer{};
39 gethostname(hostBuffer.data(), BUFSIZ);
40 const sentry_value_t hostContext = sentry_value_new_object();
41 sentry_value_set_by_key(hostContext, "Hostname", sentry_value_new_string(hostBuffer.data()));
43 // Parse CPU information
44 const std::filesystem::path cpuInfoPath = "/proc/cpuinfo";
45 std::string word;
46
47 findFromFile(cpuInfoPath, "^siblings", word);
48 sentry_value_set_by_key(hostContext, "Thread count", sentry_value_new_string(word.c_str()));
49 findFromFile(cpuInfoPath, "^(cpu cores)", word);
50 sentry_value_set_by_key(hostContext, "Core count", sentry_value_new_string(word.c_str()));
51 findFromFile(cpuInfoPath, "^(model name)", word);
52 sentry_value_set_by_key(hostContext, "Model", sentry_value_new_string(word.c_str()));
53 findFromFile(cpuInfoPath, "^vendor_id", word);
54 sentry_value_set_by_key(hostContext, "Vendor ID", sentry_value_new_string(word.c_str()));
55
56 sentry_set_context("Host", hostContext);
57 }
58
60 void setNetworkContext()
61 {
62 ifaddrs *ifaddr = nullptr;
63 if (getifaddrs(&ifaddr) < 0)
64 {
65 return;
66 }
67
68 // Iterate interfaces
69 const sentry_value_t networkContext = sentry_value_new_object();
70 for (const ifaddrs *ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next)
71 {
72 if (ifa->ifa_addr == nullptr || ((ifa->ifa_flags & IFF_RUNNING) == 0) ||
73 (ifa->ifa_flags & IFF_LOOPBACK) != 0)
74 {
75 continue;
76 }
77
78 switch (ifa->ifa_addr->sa_family)
79 {
80 case AF_INET: {
81 std::array<char, INET_ADDRSTRLEN> host{};
82 inet_ntop(AF_INET, &(std::bit_cast<sockaddr_in *>(ifa->ifa_addr))->sin_addr, host.data(),
83 INET_ADDRSTRLEN);
84 sentry_value_set_by_key(networkContext, (std::string(ifa->ifa_name) + ".ipv4").c_str(),
85 sentry_value_new_string(host.data()));
86 break;
87 }
88 case AF_INET6: {
89 std::array<char, INET6_ADDRSTRLEN> host{};
90 inet_ntop(AF_INET6, &(std::bit_cast<sockaddr_in6 *>(ifa->ifa_addr))->sin6_addr, host.data(),
91 INET6_ADDRSTRLEN);
92 sentry_value_set_by_key(networkContext, (std::string(ifa->ifa_name) + ".ipv6").c_str(),
93 sentry_value_new_string(host.data()));
94 break;
95 }
96 case AF_PACKET: {
97 std::array<char, MAC_LEN> host{};
98 if (const auto *sock = std::bit_cast<sockaddr_ll *>(ifa->ifa_addr);
99 std::format_to_n(host.data(), MAC_LEN, "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
100 sock->sll_addr[0], sock->sll_addr[1], sock->sll_addr[2], sock->sll_addr[3],
101 sock->sll_addr[4], sock->sll_addr[5])
102 .size > 0)
103 {
104 sentry_value_set_by_key(networkContext, (std::string(ifa->ifa_name) + ".mac").c_str(),
105 sentry_value_new_string(host.data()));
106 }
107 break;
108 }
109 default:
110 break;
111 }
112 }
113 freeifaddrs(ifaddr);
114
115 sentry_set_context("Network", networkContext);
116 }
117} // namespace
118
119namespace spdlog::sinks
120{
121 template <typename Mutex> sentry_api_sink<Mutex>::sentry_api_sink(const std::string &sentryAddress)
122 {
123 if (sentryAddress.empty())
124 {
125 return;
126 }
127 _sentryAvailable = true;
128
129 // Set options
130 sentry_options_t *sentryOptions = sentry_options_new();
131 sentry_options_set_release(sentryOptions, PROJECT_FULL_REVISION);
132 sentry_options_set_dsn(sentryOptions, sentryAddress.c_str());
133
134 // Init
135 sentry_init(sentryOptions);
136
137 // Tags
138 sentry_set_tag("compiler.name", COMPILER_NAME);
139 sentry_set_tag("compiler.version", COMPILER_VERSION);
140 sentry_set_tag("build", BUILD_TYPE);
141
142 /* ################################################################################### */
143 /* ############################# MAKE MODIFICATIONS HERE ############################# */
144 /* ################################################################################### */
145
146 /* ################################################################################### */
147 /* ################################ END MODIFICATIONS ################################ */
148 /* ################################################################################### */
149
150 setVersionContext();
151 setHostContext();
152 setNetworkContext();
153 }
154
155 template <typename Mutex> sentry_api_sink<Mutex>::~sentry_api_sink() { sentry_close(); }
156
157 template <typename Mutex> void sentry_api_sink<Mutex>::sink_it_(const details::log_msg &msg)
158 {
159 if (!_sentryAvailable)
160 {
161 return;
162 }
163 switch (msg.level)
164 {
165 case spdlog::level::warn:
166 sentry_capture_event(sentry_value_new_message_event(
167 SENTRY_LEVEL_WARNING, "main", std::string(msg.payload.data(), msg.payload.size()).c_str()));
168 break;
169 case spdlog::level::err:
170 sentry_capture_event(sentry_value_new_message_event(
171 SENTRY_LEVEL_ERROR, "main", std::string(msg.payload.data(), msg.payload.size()).c_str()));
172 break;
173 case spdlog::level::critical:
174 sentry_capture_event(sentry_value_new_message_event(
175 SENTRY_LEVEL_FATAL, "main", std::string(msg.payload.data(), msg.payload.size()).c_str()));
176 break;
177 case spdlog::level::trace:
178 case spdlog::level::debug:
179 case spdlog::level::info:
180 case spdlog::level::off:
181 // For lower levels, do nothing for now. But you can easily handle them here.
182 break;
183 default:
184 break;
185 }
186 }
187
188 template <typename Mutex> void sentry_api_sink<Mutex>::flush_()
189 {
190 // Sentry library handles all operations, so no need to flush
191 }
192
193 template class sentry_api_sink<std::mutex>;
195} // namespace spdlog::sinks
std::vector< std::string > findFromFile(const std::filesystem::path &filePath, const std::string &pattern, std::string &lastWord)
constexpr int MAC_LEN
Definition Sentry.cpp:19
sentry_api_sink(const std::string &sentryAddress)
Definition Sentry.cpp:121
void sink_it_(const details::log_msg &msg) override
Definition Sentry.cpp:157