log.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753
  1. #include "log.h"
  2. #include "log_settings.h"
  3. #include <library/cpp/monlib/service/pages/templates.h>
  4. static_assert(int(NActors::NLog::PRI_EMERG) == int(::TLOG_EMERG), "expect int(NActors::NLog::PRI_EMERG) == int(::TLOG_EMERG)");
  5. static_assert(int(NActors::NLog::PRI_ALERT) == int(::TLOG_ALERT), "expect int(NActors::NLog::PRI_ALERT) == int(::TLOG_ALERT)");
  6. static_assert(int(NActors::NLog::PRI_CRIT) == int(::TLOG_CRIT), "expect int(NActors::NLog::PRI_CRIT) == int(::TLOG_CRIT)");
  7. static_assert(int(NActors::NLog::PRI_ERROR) == int(::TLOG_ERR), "expect int(NActors::NLog::PRI_ERROR) == int(::TLOG_ERR)");
  8. static_assert(int(NActors::NLog::PRI_WARN) == int(::TLOG_WARNING), "expect int(NActors::NLog::PRI_WARN) == int(::TLOG_WARNING)");
  9. static_assert(int(NActors::NLog::PRI_NOTICE) == int(::TLOG_NOTICE), "expect int(NActors::NLog::PRI_NOTICE) == int(::TLOG_NOTICE)");
  10. static_assert(int(NActors::NLog::PRI_INFO) == int(::TLOG_INFO), "expect int(NActors::NLog::PRI_INFO) == int(::TLOG_INFO)");
  11. static_assert(int(NActors::NLog::PRI_DEBUG) == int(::TLOG_DEBUG), "expect int(NActors::NLog::PRI_DEBUG) == int(::TLOG_DEBUG)");
  12. static_assert(int(NActors::NLog::PRI_TRACE) == int(::TLOG_RESOURCES), "expect int(NActors::NLog::PRI_TRACE) == int(::TLOG_RESOURCES)");
  13. namespace {
  14. struct TRecordWithNewline {
  15. ELogPriority Priority;
  16. TTempBuf Buf;
  17. TRecordWithNewline(const TLogRecord& rec)
  18. : Priority(rec.Priority)
  19. , Buf(rec.Len + 1)
  20. {
  21. Buf.Append(rec.Data, rec.Len);
  22. *Buf.Proceed(1) = '\n';
  23. }
  24. operator TLogRecord() const {
  25. return TLogRecord(Priority, Buf.Data(), Buf.Filled());
  26. }
  27. };
  28. }
  29. namespace NActors {
  30. class TLoggerCounters : public ILoggerMetrics {
  31. public:
  32. TLoggerCounters(TIntrusivePtr<NMonitoring::TDynamicCounters> counters)
  33. : DynamicCounters(counters)
  34. {
  35. ActorMsgs_ = DynamicCounters->GetCounter("ActorMsgs", true);
  36. DirectMsgs_ = DynamicCounters->GetCounter("DirectMsgs", true);
  37. LevelRequests_ = DynamicCounters->GetCounter("LevelRequests", true);
  38. IgnoredMsgs_ = DynamicCounters->GetCounter("IgnoredMsgs", true);
  39. DroppedMsgs_ = DynamicCounters->GetCounter("DroppedMsgs", true);
  40. AlertMsgs_ = DynamicCounters->GetCounter("AlertMsgs", true);
  41. EmergMsgs_ = DynamicCounters->GetCounter("EmergMsgs", true);
  42. }
  43. ~TLoggerCounters() = default;
  44. void IncActorMsgs() override {
  45. ++*ActorMsgs_;
  46. }
  47. void IncDirectMsgs() override {
  48. ++*DirectMsgs_;
  49. }
  50. void IncLevelRequests() override {
  51. ++*LevelRequests_;
  52. }
  53. void IncIgnoredMsgs() override {
  54. ++*IgnoredMsgs_;
  55. }
  56. void IncAlertMsgs() override {
  57. ++*AlertMsgs_;
  58. }
  59. void IncEmergMsgs() override {
  60. ++*EmergMsgs_;
  61. }
  62. void IncDroppedMsgs() override {
  63. DroppedMsgs_->Inc();
  64. };
  65. void GetOutputHtml(IOutputStream& str) override {
  66. HTML(str) {
  67. DIV_CLASS("row") {
  68. DIV_CLASS("col-md-12") {
  69. TAG(TH4) {
  70. str << "Counters" << Endl;
  71. }
  72. DynamicCounters->OutputHtml(str);
  73. }
  74. }
  75. }
  76. }
  77. private:
  78. NMonitoring::TDynamicCounters::TCounterPtr ActorMsgs_;
  79. NMonitoring::TDynamicCounters::TCounterPtr DirectMsgs_;
  80. NMonitoring::TDynamicCounters::TCounterPtr LevelRequests_;
  81. NMonitoring::TDynamicCounters::TCounterPtr IgnoredMsgs_;
  82. NMonitoring::TDynamicCounters::TCounterPtr AlertMsgs_;
  83. NMonitoring::TDynamicCounters::TCounterPtr EmergMsgs_;
  84. // Dropped while the logger backend was unavailable
  85. NMonitoring::TDynamicCounters::TCounterPtr DroppedMsgs_;
  86. TIntrusivePtr<NMonitoring::TDynamicCounters> DynamicCounters;
  87. };
  88. class TLoggerMetrics : public ILoggerMetrics {
  89. public:
  90. TLoggerMetrics(std::shared_ptr<NMonitoring::TMetricRegistry> metrics)
  91. : Metrics(metrics)
  92. {
  93. ActorMsgs_ = Metrics->Rate(NMonitoring::TLabels{{"sensor", "logger.actor_msgs"}});
  94. DirectMsgs_ = Metrics->Rate(NMonitoring::TLabels{{"sensor", "logger.direct_msgs"}});
  95. LevelRequests_ = Metrics->Rate(NMonitoring::TLabels{{"sensor", "logger.level_requests"}});
  96. IgnoredMsgs_ = Metrics->Rate(NMonitoring::TLabels{{"sensor", "logger.ignored_msgs"}});
  97. DroppedMsgs_ = Metrics->Rate(NMonitoring::TLabels{{"sensor", "logger.dropped_msgs"}});
  98. AlertMsgs_ = Metrics->Rate(NMonitoring::TLabels{{"sensor", "logger.alert_msgs"}});
  99. EmergMsgs_ = Metrics->Rate(NMonitoring::TLabels{{"sensor", "logger.emerg_msgs"}});
  100. }
  101. ~TLoggerMetrics() = default;
  102. void IncActorMsgs() override {
  103. ActorMsgs_->Inc();
  104. }
  105. void IncDirectMsgs() override {
  106. DirectMsgs_->Inc();
  107. }
  108. void IncLevelRequests() override {
  109. LevelRequests_->Inc();
  110. }
  111. void IncIgnoredMsgs() override {
  112. IgnoredMsgs_->Inc();
  113. }
  114. void IncAlertMsgs() override {
  115. AlertMsgs_->Inc();
  116. }
  117. void IncEmergMsgs() override {
  118. EmergMsgs_->Inc();
  119. }
  120. void IncDroppedMsgs() override {
  121. DroppedMsgs_->Inc();
  122. };
  123. void GetOutputHtml(IOutputStream& str) override {
  124. HTML(str) {
  125. DIV_CLASS("row") {
  126. DIV_CLASS("col-md-12") {
  127. TAG(TH4) {
  128. str << "Metrics" << Endl;
  129. }
  130. // TODO: Now, TMetricRegistry does not have the GetOutputHtml function
  131. }
  132. }
  133. }
  134. }
  135. private:
  136. NMonitoring::TRate* ActorMsgs_;
  137. NMonitoring::TRate* DirectMsgs_;
  138. NMonitoring::TRate* LevelRequests_;
  139. NMonitoring::TRate* IgnoredMsgs_;
  140. NMonitoring::TRate* AlertMsgs_;
  141. NMonitoring::TRate* EmergMsgs_;
  142. // Dropped while the logger backend was unavailable
  143. NMonitoring::TRate* DroppedMsgs_;
  144. std::shared_ptr<NMonitoring::TMetricRegistry> Metrics;
  145. };
  146. TAtomic TLoggerActor::IsOverflow = 0;
  147. TLoggerActor::TLoggerActor(TIntrusivePtr<NLog::TSettings> settings,
  148. TAutoPtr<TLogBackend> logBackend,
  149. TIntrusivePtr<NMonitoring::TDynamicCounters> counters)
  150. : TActor(&TLoggerActor::StateFunc)
  151. , Settings(settings)
  152. , LogBackend(logBackend.Release())
  153. , Metrics(std::make_unique<TLoggerCounters>(counters))
  154. {
  155. }
  156. TLoggerActor::TLoggerActor(TIntrusivePtr<NLog::TSettings> settings,
  157. std::shared_ptr<TLogBackend> logBackend,
  158. TIntrusivePtr<NMonitoring::TDynamicCounters> counters)
  159. : TActor(&TLoggerActor::StateFunc)
  160. , Settings(settings)
  161. , LogBackend(logBackend)
  162. , Metrics(std::make_unique<TLoggerCounters>(counters))
  163. {
  164. }
  165. TLoggerActor::TLoggerActor(TIntrusivePtr<NLog::TSettings> settings,
  166. TAutoPtr<TLogBackend> logBackend,
  167. std::shared_ptr<NMonitoring::TMetricRegistry> metrics)
  168. : TActor(&TLoggerActor::StateFunc)
  169. , Settings(settings)
  170. , LogBackend(logBackend.Release())
  171. , Metrics(std::make_unique<TLoggerMetrics>(metrics))
  172. {
  173. }
  174. TLoggerActor::TLoggerActor(TIntrusivePtr<NLog::TSettings> settings,
  175. std::shared_ptr<TLogBackend> logBackend,
  176. std::shared_ptr<NMonitoring::TMetricRegistry> metrics)
  177. : TActor(&TLoggerActor::StateFunc)
  178. , Settings(settings)
  179. , LogBackend(logBackend)
  180. , Metrics(std::make_unique<TLoggerMetrics>(metrics))
  181. {
  182. }
  183. TLoggerActor::~TLoggerActor() {
  184. }
  185. void TLoggerActor::Log(TInstant time, NLog::EPriority priority, NLog::EComponent component, const char* c, ...) {
  186. Metrics->IncDirectMsgs();
  187. if (Settings && Settings->Satisfies(priority, component, 0ull)) {
  188. va_list params;
  189. va_start(params, c);
  190. TString formatted;
  191. vsprintf(formatted, c, params);
  192. auto ok = OutputRecord(time, NLog::EPrio(priority), component, formatted);
  193. Y_UNUSED(ok);
  194. va_end(params);
  195. }
  196. }
  197. void TLoggerActor::Throttle(const NLog::TSettings& settings) {
  198. if (AtomicGet(IsOverflow))
  199. Sleep(settings.ThrottleDelay);
  200. }
  201. void TLoggerActor::LogIgnoredCount(TInstant now) {
  202. TString message = Sprintf("Ignored IgnoredCount# %" PRIu64 " log records due to logger overflow!", IgnoredCount);
  203. if (!OutputRecord(now, NActors::NLog::EPrio::Error, Settings->LoggerComponent, message)) {
  204. BecomeDefunct();
  205. }
  206. }
  207. void TLoggerActor::HandleIgnoredEvent(TLogIgnored::TPtr& ev, const NActors::TActorContext& ctx) {
  208. Y_UNUSED(ev);
  209. LogIgnoredCount(ctx.Now());
  210. IgnoredCount = 0;
  211. PassedCount = 0;
  212. }
  213. void TLoggerActor::HandleIgnoredEventDrop() {
  214. // logger backend is unavailable, just ignore
  215. }
  216. void TLoggerActor::WriteMessageStat(const NLog::TEvLog& ev) {
  217. Metrics->IncActorMsgs();
  218. const auto prio = ev.Level.ToPrio();
  219. switch (prio) {
  220. case ::NActors::NLog::EPrio::Alert:
  221. Metrics->IncAlertMsgs();
  222. break;
  223. case ::NActors::NLog::EPrio::Emerg:
  224. Metrics->IncEmergMsgs();
  225. break;
  226. default:
  227. break;
  228. }
  229. }
  230. void TLoggerActor::HandleLogEvent(NLog::TEvLog::TPtr& ev, const NActors::TActorContext& ctx) {
  231. i64 delayMillisec = (ctx.Now() - ev->Get()->Stamp).MilliSeconds();
  232. WriteMessageStat(*ev->Get());
  233. if (Settings->AllowDrop) {
  234. // Disable throttling if it was enabled previously
  235. if (AtomicGet(IsOverflow))
  236. AtomicSet(IsOverflow, 0);
  237. // Check if some records have to be dropped
  238. if ((PassedCount > 10 && delayMillisec > (i64)Settings->TimeThresholdMs) || IgnoredCount > 0) {
  239. Metrics->IncIgnoredMsgs();
  240. if (IgnoredCount == 0) {
  241. ctx.Send(ctx.SelfID, new TLogIgnored());
  242. }
  243. ++IgnoredCount;
  244. PassedCount = 0;
  245. return;
  246. }
  247. PassedCount++;
  248. } else {
  249. // Enable of disable throttling depending on the load
  250. if (delayMillisec > (i64)Settings->TimeThresholdMs && !AtomicGet(IsOverflow))
  251. AtomicSet(IsOverflow, 1);
  252. else if (delayMillisec <= (i64)Settings->TimeThresholdMs && AtomicGet(IsOverflow))
  253. AtomicSet(IsOverflow, 0);
  254. }
  255. const auto prio = ev->Get()->Level.ToPrio();
  256. if (!OutputRecord(ev->Get()->Stamp, prio, ev->Get()->Component, ev->Get()->Line)) {
  257. BecomeDefunct();
  258. }
  259. }
  260. void TLoggerActor::BecomeDefunct() {
  261. Become(&TThis::StateDefunct);
  262. Schedule(WakeupInterval, new TEvents::TEvWakeup);
  263. }
  264. void TLoggerActor::HandleLogComponentLevelRequest(TLogComponentLevelRequest::TPtr& ev, const NActors::TActorContext& ctx) {
  265. Metrics->IncLevelRequests();
  266. TString explanation;
  267. int code = Settings->SetLevel(ev->Get()->Priority, ev->Get()->Component, explanation);
  268. ctx.Send(ev->Sender, new TLogComponentLevelResponse(code, explanation));
  269. }
  270. void TLoggerActor::RenderComponentPriorities(IOutputStream& str) {
  271. using namespace NLog;
  272. HTML(str) {
  273. TAG(TH4) {
  274. str << "Priority Settings for the Components";
  275. }
  276. TABLE_SORTABLE_CLASS("table") {
  277. TABLEHEAD() {
  278. TABLER() {
  279. TABLEH() {
  280. str << "Component";
  281. }
  282. TABLEH() {
  283. str << "Level";
  284. }
  285. TABLEH() {
  286. str << "Sampling Level";
  287. }
  288. TABLEH() {
  289. str << "Sampling Rate";
  290. }
  291. }
  292. }
  293. TABLEBODY() {
  294. for (EComponent i = Settings->MinVal; i < Settings->MaxVal; i++) {
  295. auto name = Settings->ComponentName(i);
  296. if (!*name)
  297. continue;
  298. NLog::TComponentSettings componentSettings = Settings->GetComponentSettings(i);
  299. TABLER() {
  300. TABLED() {
  301. str << "<a href='logger?c=" << i << "'>" << name << "</a>";
  302. }
  303. TABLED() {
  304. str << PriorityToString(EPrio(componentSettings.Raw.X.Level));
  305. }
  306. TABLED() {
  307. str << PriorityToString(EPrio(componentSettings.Raw.X.SamplingLevel));
  308. }
  309. TABLED() {
  310. str << componentSettings.Raw.X.SamplingRate;
  311. }
  312. }
  313. }
  314. }
  315. }
  316. }
  317. }
  318. /*
  319. * Logger INFO:
  320. * 1. Current priority settings from components
  321. * 2. Number of log messages (via actors events, directly)
  322. * 3. Number of messages per components, per priority
  323. * 4. Log level changes (last N changes)
  324. */
  325. void TLoggerActor::HandleMonInfo(NMon::TEvHttpInfo::TPtr& ev, const TActorContext& ctx) {
  326. const auto& params = ev->Get()->Request.GetParams();
  327. NLog::EComponent component = NLog::InvalidComponent;
  328. NLog::EPriority priority = NLog::PRI_DEBUG;
  329. NLog::EPriority samplingPriority = NLog::PRI_DEBUG;
  330. ui32 samplingRate = 0;
  331. bool hasComponent = false;
  332. bool hasPriority = false;
  333. bool hasSamplingPriority = false;
  334. bool hasSamplingRate = false;
  335. bool hasAllowDrop = false;
  336. int allowDrop = 0;
  337. if (params.Has("c")) {
  338. if (TryFromString(params.Get("c"), component) && (component == NLog::InvalidComponent || Settings->IsValidComponent(component))) {
  339. hasComponent = true;
  340. if (params.Has("p")) {
  341. int rawPriority;
  342. if (TryFromString(params.Get("p"), rawPriority) && NLog::TSettings::IsValidPriority((NLog::EPriority)rawPriority)) {
  343. priority = (NLog::EPriority)rawPriority;
  344. hasPriority = true;
  345. }
  346. }
  347. if (params.Has("sp")) {
  348. int rawPriority;
  349. if (TryFromString(params.Get("sp"), rawPriority) && NLog::TSettings::IsValidPriority((NLog::EPriority)rawPriority)) {
  350. samplingPriority = (NLog::EPriority)rawPriority;
  351. hasSamplingPriority = true;
  352. }
  353. }
  354. if (params.Has("sr")) {
  355. if (TryFromString(params.Get("sr"), samplingRate)) {
  356. hasSamplingRate = true;
  357. }
  358. }
  359. }
  360. }
  361. if (params.Has("allowdrop")) {
  362. if (TryFromString(params.Get("allowdrop"), allowDrop)) {
  363. hasAllowDrop = true;
  364. }
  365. }
  366. TStringStream str;
  367. if (hasComponent && !hasPriority && !hasSamplingPriority && !hasSamplingRate) {
  368. NLog::TComponentSettings componentSettings = Settings->GetComponentSettings(component);
  369. ui32 samplingRate = componentSettings.Raw.X.SamplingRate;
  370. HTML(str) {
  371. DIV_CLASS("row") {
  372. DIV_CLASS("col-md-12") {
  373. TAG(TH4) {
  374. str << "Current log settings for " << Settings->ComponentName(component) << Endl;
  375. }
  376. UL() {
  377. LI() {
  378. str << "Priority: "
  379. << NLog::PriorityToString(NLog::EPrio(componentSettings.Raw.X.Level));
  380. }
  381. LI() {
  382. str << "Sampling priority: "
  383. << NLog::PriorityToString(NLog::EPrio(componentSettings.Raw.X.SamplingLevel));
  384. }
  385. LI() {
  386. str << "Sampling rate: "
  387. << samplingRate;
  388. }
  389. }
  390. }
  391. }
  392. DIV_CLASS("row") {
  393. DIV_CLASS("col-md-12") {
  394. TAG(TH4) {
  395. str << "Change priority" << Endl;
  396. }
  397. UL() {
  398. for (int p = NLog::PRI_EMERG; p <= NLog::PRI_TRACE; ++p) {
  399. LI() {
  400. str << "<a href='logger?c=" << component << "&p=" << p << "'>"
  401. << NLog::PriorityToString(NLog::EPrio(p)) << "</a>";
  402. }
  403. }
  404. }
  405. TAG(TH4) {
  406. str << "Change sampling priority" << Endl;
  407. }
  408. UL() {
  409. for (int p = NLog::PRI_EMERG; p <= NLog::PRI_TRACE; ++p) {
  410. LI() {
  411. str << "<a href='logger?c=" << component << "&sp=" << p << "'>"
  412. << NLog::PriorityToString(NLog::EPrio(p)) << "</a>";
  413. }
  414. }
  415. }
  416. TAG(TH4) {
  417. str << "Change sampling rate" << Endl;
  418. }
  419. str << "<form method=\"GET\">" << Endl;
  420. str << "Rate: <input type=\"number\" name=\"sr\" value=\"" << samplingRate << "\"/>" << Endl;
  421. str << "<input type=\"hidden\" name=\"c\" value=\"" << component << "\">" << Endl;
  422. str << "<input class=\"btn btn-primary\" type=\"submit\" value=\"Change\"/>" << Endl;
  423. str << "</form>" << Endl;
  424. TAG(TH4) {
  425. str << "<a href='logger'>Cancel</a>" << Endl;
  426. }
  427. }
  428. }
  429. }
  430. } else {
  431. TString explanation;
  432. if (hasComponent && hasPriority) {
  433. Settings->SetLevel(priority, component, explanation);
  434. }
  435. if (hasComponent && hasSamplingPriority) {
  436. Settings->SetSamplingLevel(samplingPriority, component, explanation);
  437. }
  438. if (hasComponent && hasSamplingRate) {
  439. Settings->SetSamplingRate(samplingRate, component, explanation);
  440. }
  441. if (hasAllowDrop) {
  442. Settings->SetAllowDrop(allowDrop);
  443. }
  444. HTML(str) {
  445. if (!explanation.empty()) {
  446. DIV_CLASS("row") {
  447. DIV_CLASS("col-md-12 alert alert-info") {
  448. str << explanation;
  449. }
  450. }
  451. }
  452. DIV_CLASS("row") {
  453. DIV_CLASS("col-md-6") {
  454. RenderComponentPriorities(str);
  455. }
  456. DIV_CLASS("col-md-6") {
  457. TAG(TH4) {
  458. str << "Change priority for all components";
  459. }
  460. TABLE_CLASS("table table-condensed") {
  461. TABLEHEAD() {
  462. TABLER() {
  463. TABLEH() {
  464. str << "Priority";
  465. }
  466. }
  467. }
  468. TABLEBODY() {
  469. for (int p = NLog::PRI_EMERG; p <= NLog::PRI_TRACE; ++p) {
  470. TABLER() {
  471. TABLED() {
  472. str << "<a href = 'logger?c=-1&p=" << p << "'>"
  473. << NLog::PriorityToString(NLog::EPrio(p)) << "</a>";
  474. }
  475. }
  476. }
  477. }
  478. }
  479. TAG(TH4) {
  480. str << "Change sampling priority for all components";
  481. }
  482. TABLE_CLASS("table table-condensed") {
  483. TABLEHEAD() {
  484. TABLER() {
  485. TABLEH() {
  486. str << "Priority";
  487. }
  488. }
  489. }
  490. TABLEBODY() {
  491. for (int p = NLog::PRI_EMERG; p <= NLog::PRI_TRACE; ++p) {
  492. TABLER() {
  493. TABLED() {
  494. str << "<a href = 'logger?c=-1&sp=" << p << "'>"
  495. << NLog::PriorityToString(NLog::EPrio(p)) << "</a>";
  496. }
  497. }
  498. }
  499. }
  500. }
  501. TAG(TH4) {
  502. str << "Change sampling rate for all components";
  503. }
  504. str << "<form method=\"GET\">" << Endl;
  505. str << "Rate: <input type=\"number\" name=\"sr\" value=\"0\"/>" << Endl;
  506. str << "<input type=\"hidden\" name=\"c\" value=\"-1\">" << Endl;
  507. str << "<input class=\"btn btn-primary\" type=\"submit\" value=\"Change\"/>" << Endl;
  508. str << "</form>" << Endl;
  509. TAG(TH4) {
  510. str << "Drop log entries in case of overflow: "
  511. << (Settings->AllowDrop ? "Enabled" : "Disabled");
  512. }
  513. str << "<form method=\"GET\">" << Endl;
  514. str << "<input type=\"hidden\" name=\"allowdrop\" value=\"" << (Settings->AllowDrop ? "0" : "1") << "\"/>" << Endl;
  515. str << "<input class=\"btn btn-primary\" type=\"submit\" value=\"" << (Settings->AllowDrop ? "Disable" : "Enable") << "\"/>" << Endl;
  516. str << "</form>" << Endl;
  517. }
  518. }
  519. Metrics->GetOutputHtml(str);
  520. }
  521. }
  522. ctx.Send(ev->Sender, new NMon::TEvHttpInfoRes(str.Str()));
  523. }
  524. constexpr size_t TimeBufSize = 512;
  525. bool TLoggerActor::OutputRecord(TInstant time, NLog::EPrio priority, NLog::EComponent component,
  526. const TString& formatted) noexcept try {
  527. const auto logPrio = ::ELogPriority(ui16(priority));
  528. char buf[TimeBufSize];
  529. switch (Settings->Format) {
  530. case NActors::NLog::TSettings::PLAIN_FULL_FORMAT: {
  531. TStringBuilder logRecord;
  532. if (Settings->UseLocalTimestamps) {
  533. logRecord << FormatLocalTimestamp(time, buf);
  534. } else {
  535. logRecord << time;
  536. }
  537. logRecord
  538. << Settings->MessagePrefix
  539. << " :" << Settings->ComponentName(component)
  540. << " " << PriorityToString(priority)
  541. << ": " << formatted;
  542. LogBackend->WriteData(
  543. TLogRecord(logPrio, logRecord.data(), logRecord.size()));
  544. } break;
  545. case NActors::NLog::TSettings::PLAIN_SHORT_FORMAT: {
  546. TStringBuilder logRecord;
  547. logRecord
  548. << Settings->ComponentName(component)
  549. << ": " << formatted;
  550. LogBackend->WriteData(
  551. TLogRecord(logPrio, logRecord.data(), logRecord.size()));
  552. } break;
  553. case NActors::NLog::TSettings::JSON_FORMAT: {
  554. NJsonWriter::TBuf json;
  555. json.BeginObject()
  556. .WriteKey("@timestamp")
  557. .WriteString(Settings->UseLocalTimestamps ? FormatLocalTimestamp(time, buf) : time.ToString().data())
  558. .WriteKey("microseconds")
  559. .WriteULongLong(time.MicroSeconds())
  560. .WriteKey("host")
  561. .WriteString(Settings->ShortHostName)
  562. .WriteKey("cluster")
  563. .WriteString(Settings->ClusterName)
  564. .WriteKey("priority")
  565. .WriteString(PriorityToString(priority))
  566. .WriteKey("npriority")
  567. .WriteInt((int)priority)
  568. .WriteKey("component")
  569. .WriteString(Settings->ComponentName(component))
  570. .WriteKey("tag")
  571. .WriteString("KIKIMR")
  572. .WriteKey("revision")
  573. .WriteInt(GetProgramSvnRevision())
  574. .WriteKey("message")
  575. .WriteString(formatted)
  576. .EndObject();
  577. auto logRecord = json.Str();
  578. LogBackend->WriteData(
  579. TLogRecord(logPrio, logRecord.data(), logRecord.size()));
  580. } break;
  581. }
  582. return true;
  583. } catch (...) {
  584. return false;
  585. }
  586. void TLoggerActor::HandleLogEventDrop(const NLog::TEvLog::TPtr& ev) {
  587. WriteMessageStat(*ev->Get());
  588. Metrics->IncDroppedMsgs();
  589. }
  590. void TLoggerActor::HandleWakeup() {
  591. Become(&TThis::StateFunc);
  592. }
  593. const char* TLoggerActor::FormatLocalTimestamp(TInstant time, char* buf) {
  594. struct tm localTime;
  595. time.LocalTime(&localTime);
  596. int r = strftime(buf, TimeBufSize, "%Y-%m-%d-%H-%M-%S", &localTime);
  597. Y_VERIFY(r != 0);
  598. return buf;
  599. }
  600. TAutoPtr<TLogBackend> CreateSysLogBackend(const TString& ident,
  601. bool logPError, bool logCons) {
  602. int flags = 0;
  603. if (logPError)
  604. flags |= TSysLogBackend::LogPerror;
  605. if (logCons)
  606. flags |= TSysLogBackend::LogCons;
  607. return new TSysLogBackend(ident.data(), TSysLogBackend::TSYSLOG_LOCAL1, flags);
  608. }
  609. class TStderrBackend: public TLogBackend {
  610. public:
  611. TStderrBackend() {
  612. }
  613. void WriteData(const TLogRecord& rec) override {
  614. #ifdef _MSC_VER
  615. if (IsDebuggerPresent()) {
  616. TString x;
  617. x.reserve(rec.Len + 2);
  618. x.append(rec.Data, rec.Len);
  619. x.append('\n');
  620. OutputDebugString(x.c_str());
  621. }
  622. #endif
  623. bool isOk = false;
  624. do {
  625. try {
  626. TRecordWithNewline r(rec);
  627. Cerr.Write(r.Buf.Data(), r.Buf.Filled());
  628. isOk = true;
  629. } catch (TSystemError err) {
  630. // Interrupted system call
  631. Y_UNUSED(err);
  632. }
  633. } while (!isOk);
  634. }
  635. void ReopenLog() override {
  636. }
  637. private:
  638. const TString Indent;
  639. };
  640. class TLineFileLogBackend: public TFileLogBackend {
  641. public:
  642. TLineFileLogBackend(const TString& path)
  643. : TFileLogBackend(path)
  644. {
  645. }
  646. // Append newline after every record
  647. void WriteData(const TLogRecord& rec) override {
  648. TFileLogBackend::WriteData(TRecordWithNewline(rec));
  649. }
  650. };
  651. class TCompositeLogBackend: public TLogBackend {
  652. public:
  653. TCompositeLogBackend(TVector<TAutoPtr<TLogBackend>>&& underlyingBackends)
  654. : UnderlyingBackends(std::move(underlyingBackends))
  655. {
  656. }
  657. void WriteData(const TLogRecord& rec) override {
  658. for (auto& b: UnderlyingBackends) {
  659. b->WriteData(rec);
  660. }
  661. }
  662. void ReopenLog() override {
  663. }
  664. private:
  665. TVector<TAutoPtr<TLogBackend>> UnderlyingBackends;
  666. };
  667. TAutoPtr<TLogBackend> CreateStderrBackend() {
  668. return new TStderrBackend();
  669. }
  670. TAutoPtr<TLogBackend> CreateFileBackend(const TString& fileName) {
  671. return new TLineFileLogBackend(fileName);
  672. }
  673. TAutoPtr<TLogBackend> CreateNullBackend() {
  674. return new TNullLogBackend();
  675. }
  676. TAutoPtr<TLogBackend> CreateCompositeLogBackend(TVector<TAutoPtr<TLogBackend>>&& underlyingBackends) {
  677. return new TCompositeLogBackend(std::move(underlyingBackends));
  678. }
  679. }