Project import generated by Copybara.

GitOrigin-RevId: d9e9e3fb4e31372ec1fb43b178994ca78fa8fe70
diff --git a/static/js/framework/clientmon.js b/static/js/framework/clientmon.js
new file mode 100644
index 0000000..aa6dc0a
--- /dev/null
+++ b/static/js/framework/clientmon.js
@@ -0,0 +1,51 @@
+/* Copyright 2016 The Chromium Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file or at
+ * https://developers.google.com/open-source/licenses/bsd
+ */
+
+(function(window) {
+  'use strict';
+
+  // This code sets up a reporting mechanism for uncaught javascript errors
+  // to the server. It reports at most every THRESHOLD_MS milliseconds and
+  // each report contains error signatures with counts.
+
+  let errBuff = {};
+  let THRESHOLD_MS = 2000;
+
+  function throttle(fn) {
+    let last, timer;
+    return function() {
+      let now = Date.now();
+      if (last && now < last + THRESHOLD_MS) {
+        clearTimeout(timer);
+        timer = setTimeout(function() {
+          last = now;
+          fn.apply();
+        }, THRESHOLD_MS + last - now);
+      } else {
+        last = now;
+        fn.apply();
+      }
+    };
+  }
+  let flushErrs = throttle(function() {
+    let data = {errors: JSON.stringify(errBuff)};
+    CS_doPost('/_/clientmon.do', null, data);
+    errBuff = {};
+  });
+
+  window.addEventListener('error', function(evt) {
+    let signature = evt.message;
+    if (evt.error instanceof Error) {
+      signature += '\n' + evt.error.stack;
+    }
+    if (!errBuff[signature]) {
+      errBuff[signature] = 0;
+    }
+    errBuff[signature] += 1;
+    flushErrs();
+  });
+})(window);