LogCollection.cpp
Go to the documentation of this file.
1 #include "LogCollection.hpp"
2 
3 #include <XLink/XLinkPublicDefines.h>
4 #ifdef DEPTHAI_ENABLE_CURL
5  #include <cpr/cpr.h>
6 #endif
7 
8 #include <ghc/filesystem.hpp>
9 #include <iomanip>
10 #include <iostream>
11 #include <nlohmann/json.hpp>
12 #include <sstream>
13 #include <system_error>
14 
15 #include "build/version.hpp"
16 #include "sha1.hpp"
17 #include "utility/Environment.hpp"
18 #include "utility/Logging.hpp"
19 
20 namespace dai {
21 namespace logCollection {
22 
23 constexpr auto LOG_ENDPOINT = "https://logs.luxonis.com/logs";
24 
25 struct FileWithSHA1 {
26  std::string content;
27  std::string sha1Hash;
28 };
29 
30 std::string platformToString(XLinkPlatform_t platform) {
31  switch(platform) {
32  case X_LINK_ANY_PLATFORM:
33  return "X_LINK_ANY_PLATFORM";
34  case X_LINK_MYRIAD_X:
35  return "X_LINK_MYRIAD_X";
36  case X_LINK_MYRIAD_2:
37  return "X_LINK_MYRIAD_2";
38  default:
39  return "INVALID_ENUM_VALUE";
40  }
41 }
42 
43 std::string protocolToString(XLinkProtocol_t protocol) {
44  switch(protocol) {
45  case X_LINK_USB_VSC:
46  return "X_LINK_USB_VSC";
47  case X_LINK_USB_CDC:
48  return "X_LINK_USB_CDC";
49  case X_LINK_PCIE:
50  return "X_LINK_PCIE";
51  case X_LINK_IPC:
52  return "X_LINK_IPC";
53  case X_LINK_TCP_IP:
54  return "X_LINK_TCP_IP";
55  case X_LINK_NMB_OF_PROTOCOLS:
56  return "X_LINK_NMB_OF_PROTOCOLS";
57  case X_LINK_ANY_PROTOCOL:
58  return "X_LINK_ANY_PROTOCOL";
59  default:
60  return "INVALID_ENUM_VALUE";
61  }
62 }
63 
64 std::string getOSPlatform() {
65 #ifdef _WIN32
66  return "Windows";
67 #elif __APPLE__
68  return "MacOS";
69 #elif __linux__
70  return "Linux";
71 #else
72  return "Other";
73 #endif
74 }
75 
76 std::string calculateSHA1(const std::string& input) {
77  // We could also use SHA1 from OpenSSL and SChannel
78  SHA1 checksum;
79  checksum.update(input);
80  return checksum.final();
81 }
82 
83 #ifdef DEPTHAI_ENABLE_CURL
84 bool sendLogsToServer(const tl::optional<FileWithSHA1>& pipelineData, const tl::optional<FileWithSHA1>& crashDumpData, const dai::DeviceInfo& deviceInfo) {
85  (void)deviceInfo; // Unused for now
86  // At least one of the files must be present
87  if(!pipelineData && !crashDumpData) {
88  logger::error("Incorrect usage of sendLogsToServer, at least one of the files must be present");
89  return false;
90  }
91  cpr::Multipart multipart{};
92  if(pipelineData) {
93  cpr::Buffer pipelineBuffer(pipelineData->content.begin(), pipelineData->content.end(), "pipeline.json");
94  multipart.parts.emplace_back("pipelineFile", pipelineBuffer);
95  multipart.parts.emplace_back("pipelineId", pipelineData->sha1Hash);
96  }
97 
98  if(crashDumpData) {
99  cpr::Buffer crashDumpBuffer(crashDumpData->content.begin(), crashDumpData->content.end(), "crash_dump.json");
100  multipart.parts.emplace_back("crashDumpFile", crashDumpBuffer);
101  multipart.parts.emplace_back("crashDumpId", crashDumpData->sha1Hash);
102  }
103 
104  multipart.parts.emplace_back("platform", platformToString(deviceInfo.platform));
105  multipart.parts.emplace_back("connectionType", protocolToString(deviceInfo.protocol));
106  multipart.parts.emplace_back("osPlatform", getOSPlatform());
107  std::string daiVersion = fmt::format("{}-{}", build::VERSION, build::COMMIT);
108  multipart.parts.emplace_back("depthAiVersion", std::move(daiVersion));
109  multipart.parts.emplace_back("productId", deviceInfo.getMxId());
110  auto response = cpr::Post(cpr::Url{LOG_ENDPOINT}, multipart);
111  if(response.status_code != 200) {
112  logger::info("Failed to send logs, status code: {}", response.status_code);
113  return false;
114  }
115 
116  logger::info("Logs sent successfully");
117  return true;
118 }
119 #else
121  logger::info("Not sending the logs to the server, as CURL support is disabled");
122  return false;
123 }
124 #endif
125 
126 void logPipeline(const PipelineSchema& pipelineSchema, const dai::DeviceInfo& deviceInfo) {
127  // Check if compiled without CURL support and exit early if so
128 #ifndef DEPTHAI_ENABLE_CURL
129  (void)pipelineSchema;
130  (void)deviceInfo;
131  logger::info("Compiled without CURL support, not logging pipeline.");
132 #else
133  namespace fs = ghc::filesystem;
134  // Check if logging is explicitly disabled
135  auto loggingEnabled = utility::getEnv("DEPTHAI_ENABLE_ANALYTICS_COLLECTION");
136  if(loggingEnabled.empty()) {
137  logger::info("Logging disabled");
138  return;
139  }
140 
141  auto pipelineJson = nlohmann::json(pipelineSchema);
142  std::string pipelineJsonStr = pipelineJson.dump();
143  std::string pipelineSHA1 = calculateSHA1(pipelineJsonStr);
144 
145  fs::path pipelineDir = fs::current_path() / ".cache" / "depthai" / "pipelines";
146  fs::path pipelinePath = pipelineDir / pipelineSHA1 / "pipeline.json";
147 
148  if(fs::exists(pipelinePath)) {
149  logger::info("Pipeline already logged");
150  return;
151  }
152 
153  logger::info("Pipeline not logged yet, logging...");
154  std::error_code ec;
155  fs::create_directories(pipelinePath.parent_path(), ec);
156  if(ec) {
157  logger::error("Failed to create log directory: {}", ec.message());
158  return;
159  }
160 
161  std::ofstream pipelineFile(pipelinePath);
162  pipelineFile << pipelineJsonStr;
163  pipelineFile.close();
164 
165  FileWithSHA1 pipelineData;
166  pipelineData.content = std::move(pipelineJsonStr);
167  pipelineData.sha1Hash = std::move(pipelineSHA1);
168  auto success = sendLogsToServer(pipelineData, tl::nullopt, deviceInfo);
169  if(!success) {
170  // Keep at info level to not spam in case of no internet connection
171  logger::info("Failed to send pipeline logs to server");
172  } else {
173  logger::info("Pipeline logs sent to server");
174  }
175 #endif
176 }
177 
178 void logCrashDump(const tl::optional<PipelineSchema>& pipelineSchema, const CrashDump& crashDump, const dai::DeviceInfo& deviceInfo) {
179  namespace fs = ghc::filesystem;
180  std::string crashDumpJson = crashDump.serializeToJson().dump();
181  std::string crashDumpHash = calculateSHA1(crashDumpJson);
182  fs::path logDir = fs::current_path() / ".cache" / "depthai" / "crashdumps";
183  auto crashDumpPath = utility::getEnv("DEPTHAI_CRASHDUMP");
184  fs::path crashDumpPathLocal;
185  if(crashDumpPath.empty()) {
186  crashDumpPathLocal = logDir / crashDumpHash / "crash_dump.json";
187  } else {
188  crashDumpPathLocal = crashDumpPath;
189  }
190  auto errorString = fmt::format(
191  "Device with id {} has crashed. Crash dump logs are stored in: {} - please report to developers.", deviceInfo.getMxId(), crashDumpPathLocal.string());
192 
193  std::error_code ec;
194  fs::create_directories(crashDumpPathLocal.parent_path(), ec);
195  if(ec) {
196  logger::error("Failed to create log directory: {}", ec.message());
197  return;
198  }
199 
200  std::ofstream crashDumpFile(crashDumpPathLocal);
201  crashDumpFile << crashDumpJson;
202  crashDumpFile.close();
203  logger::error(errorString);
204  // Send logs to the server if possible
205 #ifdef DEPTHAI_ENABLE_CURL
206 
207  FileWithSHA1 crashDumpData;
208  crashDumpData.content = std::move(crashDumpJson);
209  crashDumpData.sha1Hash = calculateSHA1(crashDumpJson);
210 
211  tl::optional<FileWithSHA1> pipelineData;
212  if(pipelineSchema) {
213  pipelineData = FileWithSHA1{};
214  std::string pipelineJson = nlohmann::json(*pipelineSchema).dump();
215  std::string pipelineSHA1 = calculateSHA1(pipelineJson);
216  pipelineData->content = std::move(pipelineJson);
217  pipelineData->sha1Hash = std::move(pipelineSHA1);
218  }
219 
220  // Check if logging is explicitly disabled
221  auto loggingDisabled = utility::getEnv("DEPTHAI_DISABLE_CRASHDUMP_COLLECTION");
222  if(loggingDisabled.empty()) {
223  logger::info("Logging enabled");
224  auto success = sendLogsToServer(pipelineData, crashDumpData, deviceInfo);
225  if(!success) {
226  // Keep at info level to not spam in case of no internet connection
227  logger::warn("Failed to send crash dump logs to the server.");
228  }
229  } else {
230  logger::info("Logging disabled");
231  }
232 #else
233  (void)pipelineSchema;
234 #endif
235 }
236 
237 } // namespace logCollection
238 } // namespace dai
dai::logCollection::platformToString
std::string platformToString(XLinkPlatform_t platform)
Definition: LogCollection.cpp:30
dai::logCollection::protocolToString
std::string protocolToString(XLinkProtocol_t protocol)
Definition: LogCollection.cpp:43
dai::DeviceInfo
Definition: XLinkConnection.hpp:27
Environment.hpp
dai::logCollection::sendLogsToServer
bool sendLogsToServer(const tl::optional< FileWithSHA1 > &, const tl::optional< FileWithSHA1 > &, const dai::DeviceInfo &)
Definition: LogCollection.cpp:120
dai::PipelineSchema
Definition: PipelineSchema.hpp:13
dai::logCollection::LOG_ENDPOINT
constexpr auto LOG_ENDPOINT
Definition: LogCollection.cpp:23
dai::logger::info
void info(const FormatString &fmt, Args &&...args)
Definition: Logging.hpp:78
dai::logCollection::logCrashDump
void logCrashDump(const tl::optional< PipelineSchema > &pipelineSchema, const CrashDump &crashDump, const dai::DeviceInfo &deviceInfo)
Definition: LogCollection.cpp:178
nanorpc::version::core::protocol
std::integral_constant< std::uint32_t, 1 > protocol
Definition: core.h:22
dai::CrashDump::serializeToJson
nlohmann::json serializeToJson() const
Definition: CrashDump.hpp:76
tl::nullopt
static constexpr nullopt_t nullopt
Represents an empty optional.
Definition: 3rdparty/tl/optional.hpp:663
dai::logger::warn
void warn(const FormatString &fmt, Args &&...args)
Definition: Logging.hpp:84
dai::utility::checksum
std::uint32_t checksum(const void *buffer, std::size_t size, uint32_t prevChecksum)
Definition: Checksum.cpp:6
dai::CrashDump
Definition: CrashDump.hpp:14
dai::logCollection::getOSPlatform
std::string getOSPlatform()
Definition: LogCollection.cpp:64
dai::utility::getEnv
std::string getEnv(const std::string &var)
Definition: Environment.cpp:18
nanorpc::core::detail::pack::meta::type::response
@ response
sha1.hpp
dai::logCollection::calculateSHA1
std::string calculateSHA1(const std::string &input)
Definition: LogCollection.cpp:76
dai::logger::error
void error(const FormatString &fmt, Args &&...args)
Definition: Logging.hpp:90
dai::logCollection::logPipeline
void logPipeline(const PipelineSchema &pipelineSchema, const dai::DeviceInfo &deviceInfo)
Definition: LogCollection.cpp:126
dai::logCollection::FileWithSHA1
Definition: LogCollection.cpp:25
LogCollection.hpp
dai::logCollection::FileWithSHA1::content
std::string content
Definition: LogCollection.cpp:26
dai::DeviceInfo::getMxId
std::string getMxId() const
Definition: XLinkConnection.cpp:75
tl::optional
Definition: 3rdparty/tl/optional.hpp:120
dai::DeviceInfo::protocol
XLinkProtocol_t protocol
Definition: XLinkConnection.hpp:43
dai::logCollection::FileWithSHA1::sha1Hash
std::string sha1Hash
Definition: LogCollection.cpp:27
Logging.hpp
dai::DeviceInfo::platform
XLinkPlatform_t platform
Definition: XLinkConnection.hpp:44
dai
Definition: CameraExposureOffset.hpp:6
SHA1
Definition: sha1.hpp:35


depthai
Author(s): Martin Peterlin
autogenerated on Sat Mar 22 2025 02:58:19