diff --git a/browserid/app.js b/browserid/app.js
index 8adc439ed3ca48f9e5f28e3a62d6a63eb28d795d..e31733579e0c44a46d02f9eb75f51e68a44ad8cd 100644
--- a/browserid/app.js
+++ b/browserid/app.js
@@ -81,7 +81,7 @@ function router(app) {
   // this should probably be an internal redirect
   // as soon as relative paths are figured out.
   app.get('/sign_in', function(req, res, next ) {
-    metrics.userEntry('browserid', req);
+    metrics.userEntry(req);
     res.render('dialog.ejs', {
       title: 'A Better Way to Sign In',
       layout: false,
diff --git a/browserid/lib/db_mysql.js b/browserid/lib/db_mysql.js
index 964281d49462877d7396d83a70f0c79d4ed72113..d81395526ffebd02af0c334dc50e1f2cf26b9f24 100644
--- a/browserid/lib/db_mysql.js
+++ b/browserid/lib/db_mysql.js
@@ -83,7 +83,7 @@ function logUnexpectedError(detail) {
   var where;
   try { dne; } catch (e) { where = e.stack.split('\n')[2].trim(); };
   // now log it!
-  metrics.report('db', { type: "unexpected", message: "unexpected database failure", detail: detail, where: where });
+  metrics.report('unexpected', { message: "unexpected database failure", detail: detail, where: where });
 }
 
 // open & create the mysql database
@@ -426,7 +426,7 @@ exports.pubkeysForEmail = function(email, cb) {
 exports.removeEmail = function(authenticated_email, email, cb) {
   exports.emailsBelongToSameAccount(authenticated_email, email, function(ok) {
     if (!ok) {
-      metrics.report('security', { type: 'security', msg: authenticated_email + ' attempted to delete an email that doesn\'t belong to her: ' + email });
+      metrics.report('security', { msg: authenticated_email + ' attempted to delete an email that doesn\'t belong to her: ' + email });
       cb("authenticated user doesn't have permission to remove specified email " + email);
       return;
     }
diff --git a/libs/metrics.js b/libs/metrics.js
index f05328226ee3652088b7454f5d94a19bef6a6f50..ae0aaf35434519bc129282a088ab0263038e5a9e 100644
--- a/libs/metrics.js
+++ b/libs/metrics.js
@@ -88,15 +88,18 @@ function setupLogger() {
 }
 
 // entry is an object that will get JSON'ified
-exports.report = function(category, entry) {
-  // entry must have at least a type
-  if (!entry.type)
-    throw new Error("every log entry needs a type");
-
+exports.report = function(type, entry) {
   // setup the logger if need be
   setupLogger();
 
+  // allow convenient reporting of atoms by converting
+  // atoms into objects
+  if (entry === null || typeof entry !== 'object') entry = { msg: entry };
+  if (entry.type) throw "reported metrics may not have a `type` property, that's reserved";
+  entry.type = type;
+
   // timestamp
+  if (entry.at) throw "reported metrics may not have an `at` property, that's reserved";
   entry.at = new Date().toUTCString();
 
   // if no logger, go to console (FIXME: do we really want to log to console?)
@@ -104,9 +107,8 @@ exports.report = function(category, entry) {
 };
 
 // utility function to log a bunch of stuff at user entry point
-exports.userEntry = function(category, req) {
-  exports.report(category, {
-    type: 'signin',
+exports.userEntry = function(req) {
+  exports.report('signin', {
     browser: req.headers['user-agent'],
     rp: req.headers['referer'],
     // IP address (this probably needs to be replaced with the X-forwarded-for value
diff --git a/verifier/app.js b/verifier/app.js
index 1116b881ffdce383851c9925926fd8f21d62077b..e2afb4fb2c7da528f182cae8eab00790c357c8e3 100644
--- a/verifier/app.js
+++ b/verifier/app.js
@@ -72,11 +72,10 @@ function doVerify(req, resp, next) {
         audience,
         function(payload) {
           // log it!
-          metrics.report('verifier', {
-              type: 'verify',
-                result: 'success',
-                rp: payload.audience
-            });
+          metrics.report('verify', {
+            result: 'success',
+            rp: payload.audience
+          });
           
           result = {
             status : "okay",
@@ -88,21 +87,19 @@ function doVerify(req, resp, next) {
           resp.json(result);
         },
         function(errorObj) {
-          metrics.report('verifier', {
-              type: 'verify',
-                result: 'failure',
-                rp: audience
-            });
+          metrics.report('verify', {
+            result: 'failure',
+            rp: audience
+          });
           resp.json({ status: "failure", reason: errorObj });
         }
       );
   } catch (e) {
     console.log(e.stack);
-    metrics.report('verifier', {
-        type: 'verify',
-          result: 'failure',
-          rp: audience
-          });
+    metrics.report('verify', {
+      result: 'failure',
+      rp: audience
+    });
     resp.json({ status: "failure", reason: e.toString() });
   }
 }