/Log-YAML.hpp

Primary LanguageC++BSD 2-Clause "Simplified" LicenseBSD-2-Clause

Log-YAML.hpp

Data logs optimized for parsing convenience.

Log-YAML.hpp helps you generate logs in a highly-restricted subset of YAML that is easy to parse.

Example

C++

#include "Log-YAML.hpp"

Log::Log log("log");
log.log(9);
log.log(11e-3);
log.log("doh");
log.log("x", 3.0);
log.log("x", 1);
log.log("x", "doh");
log.open("sub");
log.log("x", 3.0);
log.log("x", 1);
log.log("x", "doh");
log.close();
log.close(); // oops. do the sane thing anyway
log.log(7);
vector<int> v; 
v += 1,2,3,4,5,6,7,8,9; // (using boost::assign)
log.log(v);
cout << log.str();

Output

"log":
  "0": 9
  "1": 0.011
  "2": "doh"
  "x": 3.0
  "x'": 1
  "x''": "doh"
  "sub":
    "x": 3.0
    "x'": 1
    "x''": "doh"
  "3": 7
  "4": [1, 2, 3, 4, 5, 6, 7, 8, 9] 

Or, log as you go

Above, the object is created then dumped all at once. Sometimes you want to send your logs out, line by line, as they're created.

Log.log("log");
cerr << log.head();
cerr << log.int(9);

Auto output to stderr with tag

Log.log("log", use_stderr=true, stderr_tag="(LOG) ");
log.int(9);

Stderr Output

(LOG) "log":
(LOG)   "0": 9

Install

Just copy Log-YAML.hpp into your project and go.

XXX You do need boost - TODO include boost/type_traits.hpp here

Features

  • Header-only
  • No possible run-time errors
  • No possible parsing errors

(well if you can make an error, let me know ... it's a bug.)

Rules

  • Only two scalar types: numeric and string
  • Lists (vectors) of one type only - no lists of objects
  • Strings are quoted
  • Keys are strings
  • Keys are unique
  • Keys assigned autmatically or manually

Advice

The goal is to avoid writing parsers.

Try not to invent a mini language inside of a string. Its tempting sometimes to log something like "TEST PASSED - TIMESTAMP 602161095". That defeats the purpose. Instead, make an object like:

"TEST":
  "PASSFAIL": "PASS"
  "TIMESTAMP":  602161095

FAQ

Why not just use YAML with yaml-cpp?

YAML optimizes for readability. But not many parsers can deal with the fact that it's fine to use a list or an object as a key value.

Besides, my users have complained it's hard to build and include the monster in their simple projects.

So why not just use JSON with picojson or something?

I like picojson (and even borrowed a few lines of their code -- thanks picojson!) but you have to create a whole object before outputting it. With YAML, you can output lines as they're created and if you suddenly stop it's still valid.

For both YAML and JSON, restrictions on where you can put a key-value pair and where you can put a list complicate the casual programmer's life and cause her to give up and invent an unparsable mini-language instead.

License

Copyright Michael Fox 2017

BSD-3