summaryrefslogtreecommitdiffstats
path: root/src/log/Log.h
blob: 3a60937af5583091f2e06e9c37afaeb6a4acc389 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab

#ifndef __CEPH_LOG_LOG_H
#define __CEPH_LOG_LOG_H

#include <boost/circular_buffer.hpp>

#include <condition_variable>
#include <memory>
#include <mutex>
#include <queue>
#include <string>
#include <string_view>

#include "common/Thread.h"
#include "common/likely.h"

#include "log/Entry.h"

#include <unistd.h>

struct uuid_d;

namespace ceph {
namespace logging {

class Graylog;
class JournaldLogger;
class SubsystemMap;

class Log : private Thread
{
public:
  using Thread::is_started;

  Log(const SubsystemMap *s);
  ~Log() override;

  void set_flush_on_exit();

  void set_coarse_timestamps(bool coarse);
  void set_max_new(std::size_t n);
  void set_max_recent(std::size_t n);
  void set_log_file(std::string_view fn);
  void reopen_log_file();
  void chown_log_file(uid_t uid, gid_t gid);
  void set_log_stderr_prefix(std::string_view p);
  void set_stderr_fd(int fd);

  void flush();

  void dump_recent();

  void set_syslog_level(int log, int crash);
  void set_stderr_level(int log, int crash);
  void set_graylog_level(int log, int crash);

  void start_graylog(const std::string& host,
		     const uuid_d& fsid);
  void stop_graylog();

  void set_journald_level(int log, int crash);

  void start_journald_logger();
  void stop_journald_logger();

  std::shared_ptr<Graylog> graylog() { return m_graylog; }

  void submit_entry(Entry&& e);

  void start();
  void stop();

  /// true if the log lock is held by our thread
  bool is_inside_log_lock();

  /// induce a segv on the next log event
  void inject_segv();
  void reset_segv();

protected:
  using EntryVector = std::vector<ConcreteEntry>;

  virtual void _flush(EntryVector& q, bool crash);

private:
  using EntryRing = boost::circular_buffer<ConcreteEntry>;

  static const std::size_t DEFAULT_MAX_NEW = 100;
  static const std::size_t DEFAULT_MAX_RECENT = 10000;

  Log **m_indirect_this;

  const SubsystemMap *m_subs;

  std::mutex m_queue_mutex;
  std::mutex m_flush_mutex;
  std::condition_variable m_cond_loggers;
  std::condition_variable m_cond_flusher;

  pthread_t m_queue_mutex_holder;
  pthread_t m_flush_mutex_holder;

  EntryVector m_new;    ///< new entries
  EntryRing m_recent; ///< recent (less new) entries we've already written at low detail
  EntryVector m_flush; ///< entries to be flushed (here to optimize heap allocations)

  std::string m_log_file;
  int m_fd = -1;
  uid_t m_uid = 0;
  gid_t m_gid = 0;

  int m_fd_stderr = STDERR_FILENO;

  int m_fd_last_error = 0;  ///< last error we say writing to fd (if any)

  int m_syslog_log = -2, m_syslog_crash = -2;
  int m_stderr_log = -1, m_stderr_crash = -1;
  int m_graylog_log = -3, m_graylog_crash = -3;
  int m_journald_log = -3, m_journald_crash = -3;

  std::string m_log_stderr_prefix;
  bool do_stderr_poll = false;

  std::shared_ptr<Graylog> m_graylog;
  std::unique_ptr<JournaldLogger> m_journald;

  std::vector<char> m_log_buf;

  bool m_stop = false;

  std::size_t m_max_new = DEFAULT_MAX_NEW;

  bool m_inject_segv = false;

  void *entry() override;

  void _log_safe_write(std::string_view sv);
  void _flush_logbuf();
  void _log_message(std::string_view s, bool crash);
  void _configure_stderr();
  void _log_stderr(std::string_view strv);



};

}
}

#endif