package_build_report.cpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. #include <array>
  2. #include <atomic>
  3. #include <cstdio>
  4. #include "../../../../core/logging/log.h"
  5. #include "../../../../middleware/content/packages/tables/definition_index_table.h"
  6. #include "internal.h"
  7. namespace sunrise::client::content::items::packages {
  8. namespace {
  9. std::atomic<bool> g_reported{};
  10. std::atomic<bool> g_bucketFailureReported{};
  11. std::atomic<std::size_t> g_abilityFailureReports{};
  12. } // namespace
  13. /** @param slot Requested-set position. @param definitionIndex Native item index that failed. */
  14. void report_detail_failure(std::size_t slot, std::uint16_t definitionIndex) noexcept {
  15. std::array<char, 96> line{};
  16. const int written = std::snprintf(line.data(),
  17. line.size(),
  18. "ev=pkg stage=details result=fail slot=%zu index=%u",
  19. slot,
  20. static_cast<unsigned>(definitionIndex));
  21. if (written > 0) {
  22. core::log::write(core::log::Channel::client,
  23. core::log::Level::warn,
  24. {line.data(), static_cast<std::size_t>(written)});
  25. }
  26. }
  27. /** @param count Ability bucket rows the pass built, one per subclass and ability selection. */
  28. void report_ability_count(std::size_t count) noexcept {
  29. std::array<char, 96> line{};
  30. const int written =
  31. std::snprintf(line.data(), line.size(), "ev=pkg stage=abilities result=ok rows=%zu", count);
  32. if (written > 0) {
  33. core::log::write(core::log::Channel::client,
  34. core::log::Level::info,
  35. {line.data(), static_cast<std::size_t>(written)});
  36. }
  37. }
  38. /** Reports the precise ability boundary without flooding the periodic extraction retry. */
  39. void report_ability_failure(const char* stage,
  40. std::size_t character,
  41. std::size_t first,
  42. std::size_t second) noexcept {
  43. // Extraction retries on every boot pass, so the count is capped to keep one failure readable.
  44. constexpr std::size_t kReportLimit = 12;
  45. if (g_abilityFailureReports.fetch_add(1, std::memory_order_relaxed) >= kReportLimit) {
  46. return;
  47. }
  48. std::array<char, 176> line{};
  49. const int written = std::snprintf(line.data(),
  50. line.size(),
  51. "ev=pkg stage=ability_failure reason=%s character=%zu "
  52. "first=%zu second=%zu",
  53. stage,
  54. character,
  55. first,
  56. second);
  57. if (written > 0) {
  58. core::log::write(core::log::Channel::client,
  59. core::log::Level::warn,
  60. {line.data(), static_cast<std::size_t>(written)});
  61. }
  62. }
  63. /** Reports requested, retained, and skipped rows for the equippable-item detail closure. */
  64. void report_detail_count(std::size_t requested, std::size_t built) noexcept {
  65. std::array<char, 128> line{};
  66. const int written = std::snprintf(line.data(),
  67. line.size(),
  68. "ev=pkg stage=details result=ok requested=%zu rows=%zu "
  69. "skipped=%zu",
  70. requested,
  71. built,
  72. requested - built);
  73. if (written > 0) {
  74. core::log::write(core::log::Channel::client,
  75. core::log::Level::info,
  76. {line.data(), static_cast<std::size_t>(written)});
  77. }
  78. }
  79. /** Reports the item index-table walk and every entry it could not read. */
  80. void report_row_count(std::size_t walked,
  81. std::size_t rows,
  82. std::size_t skipped,
  83. bool truncated) noexcept {
  84. std::array<char, 128> line{};
  85. const int written = std::snprintf(line.data(),
  86. line.size(),
  87. "ev=pkg stage=rows result=ok walked=%zu rows=%zu "
  88. "skipped=%zu truncated=%u",
  89. walked,
  90. rows,
  91. skipped,
  92. static_cast<unsigned>(truncated));
  93. if (written > 0) {
  94. core::log::write(core::log::Channel::client,
  95. skipped == 0 && !truncated ? core::log::Level::info
  96. : core::log::Level::warn,
  97. {line.data(), static_cast<std::size_t>(written)});
  98. }
  99. }
  100. /** Reports the bounded exact ordinary-socket relation extracted from the installed packages. */
  101. void report_socket_plug_count(std::size_t rules,
  102. std::size_t pools,
  103. std::size_t members,
  104. std::size_t skipped) noexcept {
  105. std::array<char, 160> line{};
  106. const int written = std::snprintf(line.data(),
  107. line.size(),
  108. "ev=pkg stage=socket_plugs result=ok rules=%zu pools=%zu "
  109. "members=%zu skipped=%zu",
  110. rules,
  111. pools,
  112. members,
  113. skipped);
  114. if (written > 0) {
  115. core::log::write(core::log::Channel::client,
  116. skipped == 0 ? core::log::Level::info : core::log::Level::warn,
  117. {line.data(), static_cast<std::size_t>(written)});
  118. }
  119. }
  120. /** Reports the build-scoped catalyst catalog and its first safe failure. */
  121. void report_catalyst_catalog(const state::build_data::items::catalysts::Report& report,
  122. bool built) noexcept {
  123. std::array<char, 192> line{};
  124. const int written = std::snprintf(
  125. line.data(),
  126. line.size(),
  127. "ev=pkg stage=exotic_catalysts result=%s released=%zu placeholder=%zu unsupported=%zu "
  128. "error=%s item=0x%08X lane=%u",
  129. built ? "ok" : "fail",
  130. report.released,
  131. report.placeholder,
  132. report.unsupported,
  133. state::build_data::items::catalysts::error_name(report.error).data(),
  134. report.itemDefinitionHash,
  135. static_cast<unsigned>(report.socketLane));
  136. if (written > 0) {
  137. const core::log::Level level = !built ? core::log::Level::error
  138. : report.unsupported != 0 ? core::log::Level::warn
  139. : core::log::Level::info;
  140. core::log::write(
  141. core::log::Channel::client, level, {line.data(), static_cast<std::size_t>(written)});
  142. }
  143. }
  144. /** Reports the installed bucket definition relation used by loadout resolution. */
  145. void report_bucket_equipment_mapping(std::size_t mappedSlots) noexcept {
  146. std::array<char, 128> line{};
  147. const int written = std::snprintf(line.data(),
  148. line.size(),
  149. "ev=pkg stage=bucket_equipment result=ok rows=%zu mapped=%zu",
  150. tables::kBucketDefinitionCount,
  151. mappedSlots);
  152. if (written > 0) {
  153. core::log::write(core::log::Channel::client,
  154. core::log::Level::info,
  155. {line.data(), static_cast<std::size_t>(written)});
  156. }
  157. }
  158. /** Reports one fail-closed bucket-definition rejection without flooding extraction retries. */
  159. void report_bucket_equipment_failure(const char* stage,
  160. std::size_t first,
  161. std::size_t second) noexcept {
  162. if (g_bucketFailureReported.exchange(true, std::memory_order_relaxed)) {
  163. return;
  164. }
  165. std::array<char, 160> line{};
  166. const int written = std::snprintf(line.data(),
  167. line.size(),
  168. "ev=pkg stage=bucket_equipment result=fail reason=%s "
  169. "first=%zu second=%zu",
  170. stage,
  171. first,
  172. second);
  173. if (written > 0) {
  174. core::log::write(core::log::Channel::client,
  175. core::log::Level::warn,
  176. {line.data(), static_cast<std::size_t>(written)});
  177. }
  178. }
  179. /**
  180. * Reports the pass outcome once.
  181. * @param published Rows published, or zero on failure.
  182. * @param reason Stage the pass reached, named in the line.
  183. */
  184. void report(std::size_t published, const char* reason) noexcept {
  185. if (g_reported.exchange(true, std::memory_order_relaxed)) {
  186. return;
  187. }
  188. std::array<char, 96> line{};
  189. const int written = published != 0
  190. ? std::snprintf(line.data(),
  191. line.size(),
  192. "ev=build_data stage=items result=ok rows=%zu",
  193. published)
  194. : std::snprintf(line.data(),
  195. line.size(),
  196. "ev=build_data stage=items result=fail reason=%s",
  197. reason);
  198. if (written > 0) {
  199. core::log::write(core::log::Channel::client,
  200. published != 0 ? core::log::Level::info : core::log::Level::warn,
  201. {line.data(), static_cast<std::size_t>(written)});
  202. }
  203. }
  204. } // namespace sunrise::client::content::items::packages