]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
common: add Formatter class
authorSage Weil <sage@newdream.net>
Thu, 21 Jul 2011 19:54:00 +0000 (12:54 -0700)
committerSage Weil <sage@newdream.net>
Thu, 21 Jul 2011 20:33:29 +0000 (13:33 -0700)
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 <sage@newdream.net>
src/Makefile.am
src/common/Formatter.cc [new file with mode: 0644]
src/common/Formatter.h [new file with mode: 0644]

index b70f87866e0f19cede94fbae42753beb4d51af44..e076e7b397717a0882a91c5263dcc49267444bdf 100644 (file)
@@ -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 (file)
index 0000000..5a76e69
--- /dev/null
@@ -0,0 +1,156 @@
+
+#define LARGE_SIZE 8192
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <inttypes.h>
+
+#include <iostream>
+
+#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 (file)
index 0000000..f68cfe6
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef CEPH_FORMATTER_H
+#define CEPH_FORMATTER_H
+
+#include <ostream>
+#include <sstream>
+#include <string>
+#include <list>
+
+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<formatter_stack_entry_d> 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