From d6bb5718bb72ae780099c2810eff2d3855039e41 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Thu, 21 Jul 2011 12:54:00 -0700 Subject: [PATCH] common: add Formatter class This is based on the RGW class, but - uses a stringstream - has an additional dump_stream() method that gives you a usable ostream - handles object keys properly We should merge these implementations. Not sure if either a stringstream or the raw buffer in the rgw class is ideal. Probably output should accumulate on a bufferlist so we can avoid ever reallocating for big dumps. Signed-off-by: Sage Weil --- src/Makefile.am | 2 + src/common/Formatter.cc | 156 ++++++++++++++++++++++++++++++++++++++++ src/common/Formatter.h | 64 +++++++++++++++++ 3 files changed, 222 insertions(+) create mode 100644 src/common/Formatter.cc create mode 100644 src/common/Formatter.h diff --git a/src/Makefile.am b/src/Makefile.am index b70f87866e0f1..e076e7b397717 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -721,6 +721,7 @@ libcommon_files = \ common/signal.cc \ common/simple_spin.cc \ common/Thread.cc \ + common/Formatter.cc \ include/ceph_fs.cc \ include/ceph_hash.cc \ include/ceph_strings.cc \ @@ -887,6 +888,7 @@ noinst_HEADERS = \ common/ConfUtils.h\ common/DecayCounter.h\ common/Finisher.h\ + common/Formatter.h\ common/perf_counters.h\ common/admin_socket.h \ common/admin_socket_client.h \ diff --git a/src/common/Formatter.cc b/src/common/Formatter.cc new file mode 100644 index 0000000000000..5a76e69697d11 --- /dev/null +++ b/src/common/Formatter.cc @@ -0,0 +1,156 @@ + +#define LARGE_SIZE 8192 + +#include +#include +#include + +#include + +#include "Formatter.h" + +// ----------------------- +namespace ceph { + +void Formatter::reset() +{ + m_stack.clear(); + m_ss.clear(); + m_pending_string.clear(); +} + +void Formatter::flush(std::ostream& os) +{ + finish_pending_string(); + os << m_ss.str(); + m_ss.clear(); +} + +// ----------------------- + + +void JSONFormatter::print_comma(formatter_stack_entry_d& entry) +{ + if (entry.size) { + if (m_pretty) { + m_ss << ",\n"; + for (unsigned i=1; i < m_stack.size(); i++) + m_ss << " "; + } else { + m_ss << ","; + } + } else if (entry.is_array && m_pretty) { + m_ss << "\n"; + for (unsigned i=1; i < m_stack.size(); i++) + m_ss << " "; + } + if (entry.is_array) + m_ss << " "; +} + +void JSONFormatter::print_name(const char *name) +{ + if (m_stack.empty()) + return; + struct formatter_stack_entry_d& entry = m_stack.back(); + print_comma(entry); + if (!entry.is_array) { + if (m_pretty) { + if (entry.size) + m_ss << " "; + else + m_ss << " "; + } + m_ss << "\"" << name << "\": "; + } + ++entry.size; +} + +void JSONFormatter::open_section(const char *name, bool is_array) +{ + print_name(name); + if (is_array) + m_ss << '['; + else + m_ss << '{'; + + formatter_stack_entry_d n; + n.is_array = is_array; + m_stack.push_back(n); +} + +void JSONFormatter::open_array_section(const char *name) +{ + finish_pending_string(); + open_section(name, true); +} + +void JSONFormatter::open_object_section(const char *name) +{ + finish_pending_string(); + open_section(name, false); +} + +void JSONFormatter::close_section() +{ + finish_pending_string(); + + struct formatter_stack_entry_d& entry = m_stack.back(); + m_ss << (entry.is_array ? ']' : '}'); + m_stack.pop_back(); +} + +void JSONFormatter::finish_pending_string() +{ + struct formatter_stack_entry_d& entry = m_stack.back(); + if (entry.pending_string) { + // FIXME: escape this properly + m_ss << "\"" << m_pending_string.str() << "\""; + m_pending_string.str(std::string()); + entry.pending_string = false; + } +} + +void JSONFormatter::dump_unsigned(const char *name, uint64_t u) +{ + finish_pending_string(); + print_name(name); + m_ss << u; +} + +void JSONFormatter::dump_int(const char *name, int64_t s) +{ + finish_pending_string(); + print_name(name); + m_ss << s; +} + +void JSONFormatter::dump_string(const char *name, std::string s) +{ + finish_pending_string(); + print_name(name); + m_ss << "\"" << s << "\""; +} + +std::ostream& JSONFormatter::dump_stream(const char *name) +{ + finish_pending_string(); + print_name(name); + m_stack.back().pending_string = true; + return m_pending_string; +} + +void JSONFormatter::dump_format(const char *name, const char *fmt, ...) +{ + char buf[LARGE_SIZE]; + va_list ap; + va_start(ap, fmt); + vsnprintf(buf, LARGE_SIZE, fmt, ap); + va_end(ap); + + finish_pending_string(); + print_name(name); + m_ss << "\"" << buf << "\""; +} + +} diff --git a/src/common/Formatter.h b/src/common/Formatter.h new file mode 100644 index 0000000000000..f68cfe6305a10 --- /dev/null +++ b/src/common/Formatter.h @@ -0,0 +1,64 @@ +#ifndef CEPH_FORMATTER_H +#define CEPH_FORMATTER_H + +#include +#include +#include +#include + +namespace ceph { + +struct formatter_stack_entry_d { + int size; + bool is_array, pending_string; + formatter_stack_entry_d() : size(0), is_array(false), pending_string(false) {} +}; + +class Formatter { + public: + virtual ~Formatter() {} + + virtual void reset(); + + virtual void flush(std::ostream& os); + + virtual void open_array_section(const char *name) = 0; + virtual void open_object_section(const char *name) = 0; + virtual void close_section() = 0; + virtual void dump_unsigned(const char *name, uint64_t u) = 0; + virtual void dump_int(const char *name, int64_t s) = 0; + virtual void dump_string(const char *name, std::string s) = 0; + virtual std::ostream& dump_stream(const char *name) = 0; + virtual void dump_format(const char *name, const char *fmt, ...) = 0; + + protected: + std::stringstream m_ss, m_pending_string; + std::list m_stack; + + virtual void finish_pending_string() = 0; +}; + + +class JSONFormatter : public Formatter { + public: + void open_array_section(const char *name); + void open_object_section(const char *name); + void close_section(); + void dump_unsigned(const char *name, uint64_t u); + void dump_int(const char *name, int64_t u); + void dump_string(const char *name, std::string s); + std::ostream& dump_stream(const char *name); + void dump_format(const char *name, const char *fmt, ...); + + + JSONFormatter(bool p=false) : m_pretty(p) {} + private: + bool m_pretty; + void open_section(const char *name, bool is_array); + void print_name(const char *name); + void print_comma(formatter_stack_entry_d& entry); + void finish_pending_string(); +}; + +} +#endif -- 2.39.5