Repository: serverless/serverless (JavaScript)
Date: 2017-06-19 07:06:07+00:00
Task type: Feature

Issue:
Generate a unique uuid for each command invocation
# This is a Feature Proposal

## Description
In order to help us connect error tracking to specific commands we need a way of tying together the lifespan of a command invocation with the actual logs/errors of what has occurred. A simple way of doing this is to generate a unique uuid at the start of each command and report it with error tracking/logging.



Issue discussion:

Solution patch:
diff --git a/lib/Serverless.js b/lib/Serverless.js
index b8434173baf..b0a805ed59c 100644
--- a/lib/Serverless.js
+++ b/lib/Serverless.js
@@ -4,6 +4,7 @@ require('shelljs/global');
 
 const path = require('path');
 const BbPromise = require('bluebird');
+const uuid = require('uuid');
 const os = require('os');
 const CLI = require('./classes/CLI');
 const Config = require('./classes/Config');
@@ -18,8 +19,11 @@ const initializeErrorReporter = require('./utils/sentry').initializeErrorReporte
 
 class Serverless {
   constructor(config) {
+    // invocation id to identify single invocations
+    this.invocationId = uuid.v4();
+
     // boot up error reporting via sentry
-    initializeErrorReporter();
+    initializeErrorReporter(this.invocationId);
 
     let configObject = config;
     configObject = configObject || {};
diff --git a/lib/classes/Utils.js b/lib/classes/Utils.js
index 6091c6ea465..5c1d1305e33 100644
--- a/lib/classes/Utils.js
+++ b/lib/classes/Utils.js
@@ -136,6 +136,7 @@ class Utils {
       const config = configUtils.getConfig();
       const userId = config.frameworkId;
       const trackingDisabled = config.trackingDisabled;
+      const invocationId = serverless.invocationId;
 
       if (trackingDisabled) {
         return resolve();
@@ -257,6 +258,7 @@ class Utils {
           general: {
             userId,
             context,
+            invocationId,
             timestamp: (new Date()).getTime(),
             timezone: (new Date()).toString().match(/([A-Z]+[+-][0-9]+)/)[1],
             operatingSystem: process.platform,
diff --git a/lib/utils/sentry.js b/lib/utils/sentry.js
index 977666d54cf..34c7bd6869e 100644
--- a/lib/utils/sentry.js
+++ b/lib/utils/sentry.js
@@ -7,7 +7,7 @@ const DSN = 'https://cbb3655b343a49ee9a18494d0dd171a7:4b9ef9a2c5eb40379f30b5e680
 const SLS_DISABLE_ERROR_TRACKING = true;
 const IS_CI = ci.isCI;
 
-function initializeErrorReporter() {
+function initializeErrorReporter(invocationId) {
   const config = configUtils.getConfig();
   const trackingDisabled = config.trackingDisabled;
 
@@ -24,6 +24,7 @@ function initializeErrorReporter() {
     release: pkg.version,
     extra: {
       frameworkId: config.frameworkId,
+      invocationId,
     },
   });
 


Test patch:
diff --git a/lib/Serverless.test.js b/lib/Serverless.test.js
index b33836407b0..7095984a325 100644
--- a/lib/Serverless.test.js
+++ b/lib/Serverless.test.js
@@ -24,6 +24,10 @@ describe('Serverless', () => {
   });
 
   describe('#constructor()', () => {
+    it('should set an invocationId', () => {
+      expect(serverless.invocationId).to.match(/.+-{1}.+-{1}.+-{1}.+-{1}.+/);
+    });
+
     it('should set the correct config if a config object is passed', () => {
       const configObj = { some: 'config' };
       const serverlessWithConfig = new Serverless(configObj);
diff --git a/lib/classes/Utils.test.js b/lib/classes/Utils.test.js
index b5ac69fecf7..48e85a98848 100644
--- a/lib/classes/Utils.test.js
+++ b/lib/classes/Utils.test.js
@@ -469,6 +469,7 @@ describe('Utils', () => {
         expect(data.properties.events.eventNamesPerFunction[1][1]).to.equal('sns');
         // general property
         expect(data.properties.general.userId.length).to.be.at.least(1);
+        expect(data.properties.general.invocationId).to.match(/.+-{1}.+-{1}.+-{1}.+-{1}.+/);
         expect(data.properties.general.timestamp).to.match(/[0-9]+/);
         expect(data.properties.general.timezone.length).to.be.at.least(1);
         expect(data.properties.general.operatingSystem.length).to.be.at.least(1);