page.cpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. #include "page.h"
  2. #include "encode.h"
  3. #include <library/cpp/monlib/service/pages/templates.h>
  4. #include <library/cpp/string_utils/quote/quote.h>
  5. #include <util/string/split.h>
  6. #include <util/system/tls.h>
  7. using namespace NMonitoring;
  8. namespace {
  9. Y_POD_STATIC_THREAD(TDynamicCounters*)
  10. currentCounters(nullptr);
  11. }
  12. TMaybe<EFormat> ParseFormat(TStringBuf str) {
  13. if (str == TStringBuf("json")) {
  14. return EFormat::JSON;
  15. } else if (str == TStringBuf("spack")) {
  16. return EFormat::SPACK;
  17. } else if (str == TStringBuf("prometheus")) {
  18. return EFormat::PROMETHEUS;
  19. } else {
  20. return Nothing();
  21. }
  22. }
  23. void TDynamicCountersPage::Output(NMonitoring::IMonHttpRequest& request) {
  24. if (OutputCallback) {
  25. OutputCallback();
  26. }
  27. TString nameLabel("sensor");
  28. TCountableBase::EVisibility visibility{
  29. TCountableBase::EVisibility::Public
  30. };
  31. TVector<TStringBuf> parts;
  32. StringSplitter(request.GetPathInfo())
  33. .Split('/')
  34. .SkipEmpty()
  35. .Collect(&parts);
  36. TMaybe<EFormat> format = !parts.empty() ? ParseFormat(parts.back()) : Nothing();
  37. if (format) {
  38. parts.pop_back();
  39. }
  40. if (!parts.empty() && parts.back().StartsWith(TStringBuf("name_label="))) {
  41. TVector<TString> labels;
  42. StringSplitter(parts.back()).Split('=').SkipEmpty().Collect(&labels);
  43. if (labels.size() == 2U) {
  44. nameLabel = labels.back();
  45. }
  46. parts.pop_back();
  47. }
  48. if (!parts.empty() && parts.back() == TStringBuf("private")) {
  49. visibility = TCountableBase::EVisibility::Private;
  50. parts.pop_back();
  51. }
  52. auto counters = Counters;
  53. for (const auto& escaped : parts) {
  54. const auto part = CGIUnescapeRet(escaped);
  55. TVector<TString> labels;
  56. StringSplitter(part).Split('=').SkipEmpty().Collect(&labels);
  57. if (labels.size() != 2U)
  58. return NotFound(request);
  59. if (const auto child = counters->FindSubgroup(
  60. labels.front(),
  61. labels.back())) {
  62. counters = child;
  63. } else {
  64. return HandleAbsentSubgroup(request);
  65. }
  66. }
  67. if (!format) {
  68. currentCounters = counters.Get();
  69. THtmlMonPage::Output(request);
  70. currentCounters = nullptr;
  71. return;
  72. }
  73. IOutputStream& out = request.Output();
  74. if (*format == EFormat::JSON) {
  75. out << HTTPOKJSON;
  76. } else if (*format == EFormat::SPACK) {
  77. out << HTTPOKSPACK;
  78. } else if (*format == EFormat::PROMETHEUS) {
  79. out << HTTPOKPROMETHEUS;
  80. } else {
  81. ythrow yexception() << "unsupported metric encoding format: " << *format;
  82. }
  83. auto encoder = CreateEncoder(&out, *format, nameLabel, visibility);
  84. counters->Accept(TString(), TString(), *encoder);
  85. out.Flush();
  86. }
  87. void TDynamicCountersPage::HandleAbsentSubgroup(IMonHttpRequest& request) {
  88. if (UnknownGroupPolicy == EUnknownGroupPolicy::Error) {
  89. NotFound(request);
  90. } else if (UnknownGroupPolicy == EUnknownGroupPolicy::Ignore) {
  91. NoContent(request);
  92. } else {
  93. Y_ABORT("Unsupported policy set");
  94. }
  95. }
  96. void TDynamicCountersPage::BeforePre(IMonHttpRequest& request) {
  97. IOutputStream& out = request.Output();
  98. HTML(out) {
  99. DIV() {
  100. out << "<a href='" << request.GetPath() << "/json'>Counters as JSON</a>";
  101. out << " for Solomon";
  102. }
  103. TAG(TH5) {
  104. out << "Counters subgroups";
  105. }
  106. UL() {
  107. currentCounters->EnumerateSubgroups([&](const TString& name, const TString& value) {
  108. LI() {
  109. TString pathPart = name + "=" + value;
  110. Quote(pathPart, "");
  111. out << "\n<a href='" << request.GetPath() << "/" << pathPart << "'>" << name << " " << value << "</a>";
  112. }
  113. });
  114. }
  115. TAG(TH4) {
  116. out << "Counters as text";
  117. }
  118. }
  119. }
  120. void TDynamicCountersPage::OutputText(IOutputStream& out, IMonHttpRequest&) {
  121. currentCounters->OutputPlainText(out);
  122. }
  123. void TDynamicCountersPage::SetUnknownGroupPolicy(EUnknownGroupPolicy value) {
  124. UnknownGroupPolicy = value;
  125. }