diff --git a/docs/README.md b/docs/README.md
index b92131b9a..4fd1636cb 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -53,6 +53,7 @@ The Serverless Framework allows you to deploy auto-scaling, pay-per-execution, e
Deploy
Invoke
Logs
+ Metrics
Info
Rollback
Remove
diff --git a/docs/providers/aws/cli-reference/info.md b/docs/providers/aws/cli-reference/info.md
index f066a2ac8..22eeac745 100644
--- a/docs/providers/aws/cli-reference/info.md
+++ b/docs/providers/aws/cli-reference/info.md
@@ -1,7 +1,7 @@
@@ -76,4 +76,4 @@ CreateThumbnailsLambdaFunctionArn: arn:aws:lambda:us-east-1:377024778620:functio
TakeScreenshotLambdaFunctionArn: arn:aws:lambda:us-east-1:377024778620:function:lambda-screenshots-dev-takeScreenshot
ServiceEndpoint: https://12341jc801.execute-api.us-east-1.amazonaws.com/dev
ServerlessDeploymentBucketName: lambda-screenshots-dev-serverlessdeploymentbucket-15b7pkc04f98a
-```
\ No newline at end of file
+```
diff --git a/docs/providers/aws/cli-reference/metrics.md b/docs/providers/aws/cli-reference/metrics.md
new file mode 100644
index 000000000..5cd708acb
--- /dev/null
+++ b/docs/providers/aws/cli-reference/metrics.md
@@ -0,0 +1,47 @@
+
+
+
+### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/aws/cli-reference/metrics)
+
+
+# Metrics
+
+Lets you watch the metrics of a specific function.
+
+```bash
+serverless metrics --function hello
+```
+
+## Options
+
+- `--function` or `-f` The function you want to fetch the metrics for. **Required**
+- `--stage` or `-s` The stage you want to view the function metrics for. If not provided, the plugin will use the default stage listed in `serverless.yml`. If that doesn't exist either it'll just fetch the metrics from the `dev` stage.
+- `--region` or `-r` The region you want to view the function metrics for. If not provided, the plugin will use the default region listed in `serverless.yml`. If that doesn't exist either it'll just fetch the metrics from the `us-east-1` region.
+- `--startTime` A specific unit in time to start fetching metrics from (ie: `2010-10-20`, `1469705761`, `30m` (30 minutes ago), `2h` (2 days ago) or `3d` (3 days ago)). Date formats should be written in ISO 8601. Defaults to 24h ago.
+- `--endTime` A specific unit in time to end fetching metrics from (ie: `2010-10-21` or `1469705761`). Date formats should be written in ISO 8601. Defaults to now.
+
+## Examples
+
+**Note:** There's a small lag between invoking the function and actually having access to the metrics. It takes a few seconds for the metrics to show up right after invoking the function.
+
+### See all metrics of the last 24h
+
+```bash
+serverless metrics --function hello
+```
+
+Displays all metrics for the last 24h.
+
+### See metrics for a specific timespan
+
+```bash
+serverless metrics --function hello --startTime 1970-01-01 --endTime 1970-01-02
+```
+
+Displays all metrics for the time between January 1, 1970 and January 2, 1970.
diff --git a/docs/providers/aws/cli-reference/remove.md b/docs/providers/aws/cli-reference/remove.md
index 57e8b954e..0e7e3e457 100644
--- a/docs/providers/aws/cli-reference/remove.md
+++ b/docs/providers/aws/cli-reference/remove.md
@@ -1,7 +1,7 @@
diff --git a/docs/providers/aws/cli-reference/rollback.md b/docs/providers/aws/cli-reference/rollback.md
index 33a5e7a04..4dd4b1c0c 100644
--- a/docs/providers/aws/cli-reference/rollback.md
+++ b/docs/providers/aws/cli-reference/rollback.md
@@ -1,7 +1,7 @@
diff --git a/docs/providers/aws/cli-reference/slstats.md b/docs/providers/aws/cli-reference/slstats.md
index 0665f014d..2671f8eea 100644
--- a/docs/providers/aws/cli-reference/slstats.md
+++ b/docs/providers/aws/cli-reference/slstats.md
@@ -1,7 +1,7 @@
diff --git a/lib/plugins/Plugins.json b/lib/plugins/Plugins.json
index e88707bc1..0199a86c2 100644
--- a/lib/plugins/Plugins.json
+++ b/lib/plugins/Plugins.json
@@ -8,6 +8,7 @@
"./invoke/invoke.js",
"./info/info.js",
"./logs/logs.js",
+ "./metrics/metrics.js",
"./remove/remove.js",
"./rollback/index.js",
"./slstats/slstats.js",
@@ -17,6 +18,7 @@
"./aws/invoke/index.js",
"./aws/info/index.js",
"./aws/logs/index.js",
+ "./aws/metrics/awsMetrics.js",
"./aws/remove/index.js",
"./aws/rollback/index.js",
"./aws/deploy/compile/functions/index.js",
diff --git a/lib/plugins/aws/metrics/awsMetrics.js b/lib/plugins/aws/metrics/awsMetrics.js
new file mode 100644
index 000000000..f4e47f0dd
--- /dev/null
+++ b/lib/plugins/aws/metrics/awsMetrics.js
@@ -0,0 +1,212 @@
+'use strict';
+
+const BbPromise = require('bluebird');
+const chalk = require('chalk');
+const _ = require('lodash');
+const moment = require('moment');
+const validate = require('../lib/validate');
+
+class AwsMetrics {
+ constructor(serverless, options) {
+ this.serverless = serverless;
+ this.options = options;
+ this.provider = this.serverless.getProvider('aws');
+
+ Object.assign(this, validate);
+
+ this.hooks = {
+ 'metrics:metrics': () => BbPromise.bind(this)
+ .then(this.extendedValidate)
+ .then(this.getMetrics)
+ .then(this.showMetrics),
+ };
+ }
+
+ extendedValidate() {
+ this.validate();
+
+ // validate function exists in service
+ this.options.function = this.serverless.service.getFunction(this.options.function).name;
+
+ const today = new Date();
+ let yesterday = new Date();
+ yesterday = yesterday.setDate(yesterday.getDate() - 1);
+ yesterday = new Date(yesterday);
+
+ if (this.options.startTime) {
+ const since = (['m', 'h', 'd']
+ .indexOf(this.options.startTime[this.options.startTime.length - 1]) !== -1);
+ if (since) {
+ this.options.startTime = moment().subtract(this.options
+ .startTime.replace(/\D/g, ''), this.options
+ .startTime.replace(/\d/g, '')).valueOf();
+ }
+ } else {
+ this.options.startTime = yesterday;
+ }
+
+ this.options.endTime = this.options.endTime || today;
+
+ // finally create a new date object
+ this.options.startTime = new Date(this.options.startTime);
+ this.options.endTime = new Date(this.options.endTime);
+
+ return BbPromise.resolve();
+ }
+
+ getMetrics() {
+ const FunctionName = this.options.function;
+ const StartTime = this.options.startTime;
+ const EndTime = this.options.endTime;
+ const Namespace = 'AWS/Lambda';
+
+ const hoursDiff = Math.abs(EndTime - StartTime) / 36e5;
+ const Period = (hoursDiff > 24) ? 3600 * 24 : 3600;
+
+ const promises = [];
+
+ // get invocations
+ const invocationsPromise = this.provider.request('CloudWatch',
+ 'getMetricStatistics',
+ {
+ StartTime,
+ EndTime,
+ MetricName: 'Invocations',
+ Namespace,
+ Period,
+ Dimensions: [
+ {
+ Name: 'FunctionName',
+ Value: FunctionName,
+ },
+ ],
+ Statistics: [
+ 'Sum',
+ ],
+ Unit: 'Count',
+ },
+ this.options.stage,
+ this.options.region
+ );
+ // get throttles
+ const throttlesPromise = this.provider.request('CloudWatch',
+ 'getMetricStatistics',
+ {
+ StartTime,
+ EndTime,
+ MetricName: 'Throttles',
+ Namespace,
+ Period,
+ Dimensions: [
+ {
+ Name: 'FunctionName',
+ Value: FunctionName,
+ },
+ ],
+ Statistics: [
+ 'Sum',
+ ],
+ Unit: 'Count',
+ },
+ this.options.stage,
+ this.options.region
+ );
+ // get errors
+ const errorsPromise = this.provider.request('CloudWatch',
+ 'getMetricStatistics',
+ {
+ StartTime,
+ EndTime,
+ MetricName: 'Errors',
+ Namespace,
+ Period,
+ Dimensions: [
+ {
+ Name: 'FunctionName',
+ Value: FunctionName,
+ },
+ ],
+ Statistics: [
+ 'Sum',
+ ],
+ Unit: 'Count',
+ },
+ this.options.stage,
+ this.options.region
+ );
+ // get avg. duration
+ const avgDurationPromise = this.provider.request('CloudWatch',
+ 'getMetricStatistics',
+ {
+ StartTime,
+ EndTime,
+ MetricName: 'Duration',
+ Namespace,
+ Period,
+ Dimensions: [
+ {
+ Name: 'FunctionName',
+ Value: FunctionName,
+ },
+ ],
+ Statistics: [
+ 'Average',
+ ],
+ Unit: 'Milliseconds',
+ },
+ this.options.stage,
+ this.options.region
+ );
+
+ // push all promises to the array which will be used to resolve those
+ promises.push(invocationsPromise);
+ promises.push(throttlesPromise);
+ promises.push(errorsPromise);
+ promises.push(avgDurationPromise);
+
+ return BbPromise.all(promises).then((metrics) => metrics);
+ }
+
+ showMetrics(metrics) {
+ let message = '';
+
+ message += `${chalk.yellow.underline(this.options.function)}\n`;
+
+ const formattedStartTime = moment(this.options.startTime).format('LLL');
+ const formattedEndTime = moment(this.options.endTime).format('LLL');
+ message += `${formattedStartTime} - ${formattedEndTime}\n\n`;
+
+ if (metrics && metrics.length > 0) {
+ _.forEach(metrics, (metric) => {
+ if (metric.Label === 'Invocations') {
+ const datapoints = metric.Datapoints;
+ const invocations = datapoints
+ .reduce((previous, datapoint) => previous + datapoint.Sum, 0);
+ message += `${chalk.yellow('Invocations:', invocations, '\n')}`;
+ } else if (metric.Label === 'Throttles') {
+ const datapoints = metric.Datapoints;
+ const throttles = datapoints
+ .reduce((previous, datapoint) => previous + datapoint.Sum, 0);
+ message += `${chalk.yellow('Throttles:', throttles, '\n')}`;
+ } else if (metric.Label === 'Errors') {
+ const datapoints = metric.Datapoints;
+ const errors = datapoints
+ .reduce((previous, datapoint) => previous + datapoint.Sum, 0);
+ message += `${chalk.yellow('Errors:', errors, '\n')}`;
+ } else {
+ const datapoints = metric.Datapoints;
+ const duration = datapoints
+ .reduce((previous, datapoint) => previous + datapoint.Average, 0);
+ const formattedRoundedAvgDuration = `${Math.round(duration * 100) / 100}ms`;
+ message += `${chalk.yellow('Duration (avg.):', formattedRoundedAvgDuration)}`;
+ }
+ });
+ } else {
+ message += `${chalk.yellow('There are no metrics to show for these options')}`;
+ }
+ this.serverless.cli.consoleLog(message);
+ return BbPromise.resolve(message);
+ }
+}
+
+module.exports = AwsMetrics;
diff --git a/lib/plugins/aws/metrics/awsMetrics.test.js b/lib/plugins/aws/metrics/awsMetrics.test.js
new file mode 100644
index 000000000..d6a30f084
--- /dev/null
+++ b/lib/plugins/aws/metrics/awsMetrics.test.js
@@ -0,0 +1,319 @@
+'use strict';
+
+const expect = require('chai').expect;
+const sinon = require('sinon');
+const BbPromise = require('bluebird');
+const AwsProvider = require('../provider/awsProvider');
+const AwsMetrics = require('./awsMetrics');
+const Serverless = require('../../../Serverless');
+const CLI = require('../../../classes/CLI');
+const chalk = require('chalk');
+
+describe('AwsMetrics', () => {
+ let awsMetrics;
+ let serverless;
+
+ beforeEach(() => {
+ serverless = new Serverless();
+ serverless.cli = new CLI(serverless);
+ serverless.setProvider('aws', new AwsProvider(serverless));
+ const options = {
+ stage: 'dev',
+ region: 'us-east-1',
+ };
+ awsMetrics = new AwsMetrics(serverless, options);
+ });
+
+ describe('#constructor()', () => {
+ it('should set the serverless instance to this.serverless', () => {
+ expect(awsMetrics.serverless).to.deep.equal(serverless);
+ });
+
+ it('should set the passed in options to this.options', () => {
+ expect(awsMetrics.options).to.deep.equal({ stage: 'dev', region: 'us-east-1' });
+ });
+
+ it('should set the provider variable to the AwsProvider instance', () =>
+ expect(awsMetrics.provider).to.be.instanceof(AwsProvider));
+
+ it('should have a "metrics:metrics" hook', () => {
+ // eslint-disable-next-line no-unused-expressions
+ expect(awsMetrics.hooks['metrics:metrics']).to.not.be.undefined;
+ });
+
+ it('should run promise chain in order for "metrics:metrics" hook', () => {
+ const extendedValidateStub = sinon
+ .stub(awsMetrics, 'extendedValidate').returns(BbPromise.resolve());
+ const getMetricsStub = sinon
+ .stub(awsMetrics, 'getMetrics').returns(BbPromise.resolve());
+ const showMetricsStub = sinon
+ .stub(awsMetrics, 'showMetrics').returns(BbPromise.resolve());
+
+ return awsMetrics.hooks['metrics:metrics']().then(() => {
+ expect(extendedValidateStub.calledOnce).to.equal(true);
+ expect(getMetricsStub.calledAfter(extendedValidateStub)).to.equal(true);
+ expect(showMetricsStub.calledAfter(getMetricsStub)).to.equal(true);
+
+ awsMetrics.extendedValidate.restore();
+ awsMetrics.getMetrics.restore();
+ awsMetrics.showMetrics.restore();
+ });
+ });
+ });
+
+ describe('#extendedValidate()', () => {
+ let validateStub;
+
+ beforeEach(() => {
+ awsMetrics.serverless.service.functions = {
+ function1: {},
+ };
+ awsMetrics.serverless.service.service = 'my-service';
+ awsMetrics.options.function = 'function1';
+ validateStub = sinon
+ .stub(awsMetrics, 'validate').returns(BbPromise.resolve);
+ });
+
+ afterEach(() => {
+ awsMetrics.validate.restore();
+ });
+
+ it('should call the shared validate() function', () =>
+ awsMetrics.extendedValidate().then(() => {
+ expect(validateStub.calledOnce).to.equal(true);
+ })
+ );
+
+ it('should set the startTime to yesterday as the default value if not provided', () => {
+ awsMetrics.options.startTime = null;
+
+ let yesterday = new Date();
+ yesterday = yesterday.setDate(yesterday.getDate() - 1);
+ yesterday = new Date(yesterday);
+ const yesterdaysYear = yesterday.getFullYear();
+ const yesterdaysMonth = yesterday.getMonth() + 1;
+ const yesterdaysDay = yesterday.getDate();
+ const yesterdaysDate = `${yesterdaysYear}-${yesterdaysMonth}-${yesterdaysDay}`;
+
+ return awsMetrics.extendedValidate().then(() => {
+ const defaultsStartTime = awsMetrics.options.startTime;
+ const defaultsYear = defaultsStartTime.getFullYear();
+ const defaultsMonth = defaultsStartTime.getMonth() + 1;
+ const defaultsDay = defaultsStartTime.getDate();
+ const defaultsDate = `${defaultsYear}-${defaultsMonth}-${defaultsDay}`;
+
+ expect(defaultsDate).to.equal(yesterdaysDate);
+ });
+ });
+
+ it('should set the startTime to the provided value', () => {
+ awsMetrics.options.startTime = '1970-01-01';
+
+ return awsMetrics.extendedValidate().then(() => {
+ const startTime = awsMetrics.options.startTime.toISOString();
+ const expectedStartTime = new Date('1970-01-01').toISOString();
+
+ expect(startTime).to.equal(expectedStartTime);
+ });
+ });
+
+ it('should translate human friendly syntax (e.g. 24h) for startTime', () => {
+ awsMetrics.options.startTime = '24h'; // 24 hours ago
+
+ let yesterday = new Date();
+ yesterday = yesterday.setDate(yesterday.getDate() - 1);
+ yesterday = new Date(yesterday);
+ const yesterdaysYear = yesterday.getFullYear();
+ const yesterdaysMonth = yesterday.getMonth() + 1;
+ const yesterdaysDay = yesterday.getDate();
+ const yesterdaysDate = `${yesterdaysYear}-${yesterdaysMonth}-${yesterdaysDay}`;
+
+ return awsMetrics.extendedValidate().then(() => {
+ const translatedStartTime = awsMetrics.options.startTime;
+ const translatedYear = translatedStartTime.getFullYear();
+ const translatedMonth = translatedStartTime.getMonth() + 1;
+ const translatedDay = translatedStartTime.getDate();
+ const translatedDate = `${translatedYear}-${translatedMonth}-${translatedDay}`;
+
+ expect(translatedDate).to.equal(yesterdaysDate);
+ });
+ });
+
+ it('should set the endTime to today as the default value if not provided', () => {
+ awsMetrics.options.endTime = null;
+
+ const today = new Date();
+ const todaysYear = today.getFullYear();
+ const todaysMonth = today.getMonth() + 1;
+ const todaysDay = today.getDate();
+ const todaysDate = `${todaysYear}-${todaysMonth}-${todaysDay}`;
+
+ return awsMetrics.extendedValidate().then(() => {
+ const defaultsStartTime = awsMetrics.options.endTime;
+ const defaultsYear = defaultsStartTime.getFullYear();
+ const defaultsMonth = defaultsStartTime.getMonth() + 1;
+ const defaultsDay = defaultsStartTime.getDate();
+ const defaultsDate = `${defaultsYear}-${defaultsMonth}-${defaultsDay}`;
+
+ expect(defaultsDate).to.equal(todaysDate);
+ });
+ });
+
+ it('should set the endTime to the provided value', () => {
+ awsMetrics.options.endTime = '1970-01-01';
+
+ return awsMetrics.extendedValidate().then(() => {
+ const endTime = awsMetrics.options.endTime.toISOString();
+ const expectedEndTime = new Date('1970-01-01').toISOString();
+
+ expect(endTime).to.equal(expectedEndTime);
+ });
+ });
+ });
+
+ describe('#getMetrics()', () => {
+ let requestStub;
+
+ beforeEach(() => {
+ awsMetrics.options.function = 'function1';
+ awsMetrics.options.startTime = '1970-01-01';
+ awsMetrics.options.endTime = '1970-01-02';
+ requestStub = sinon.stub(awsMetrics.provider, 'request');
+ });
+
+ afterEach(() => {
+ awsMetrics.provider.request.restore();
+ });
+
+ it('should should gather metrics for the function', () => {
+ // invocations
+ requestStub.onCall(0).returns(
+ BbPromise.resolve({
+ ResponseMetadata: { RequestId: '1f50045b-b569-11e6-86c6-eb54d1aaa755' },
+ Label: 'Invocations',
+ Datapoints: [],
+ })
+ );
+ // throttles
+ requestStub.onCall(1).returns(
+ BbPromise.resolve({
+ ResponseMetadata: { RequestId: '1f59059b-b569-11e6-aa18-c7bab68810d2' },
+ Label: 'Throttles',
+ Datapoints: [],
+ })
+ );
+ // errors
+ requestStub.onCall(2).returns(
+ BbPromise.resolve({
+ ResponseMetadata: { RequestId: '1f50c7b1-b569-11e6-b1b6-ab86694b617b' },
+ Label: 'Errors',
+ Datapoints: [],
+ })
+ );
+ // duration
+ requestStub.onCall(3).returns(
+ BbPromise.resolve({
+ ResponseMetadata: { RequestId: '1f63db14-b569-11e6-8501-d98a275ce164' },
+ Label: 'Duration',
+ Datapoints: [],
+ })
+ );
+
+ const expectedResult = [
+ { ResponseMetadata: { RequestId: '1f50045b-b569-11e6-86c6-eb54d1aaa755' },
+ Label: 'Invocations',
+ Datapoints: [],
+ },
+ { ResponseMetadata: { RequestId: '1f59059b-b569-11e6-aa18-c7bab68810d2' },
+ Label: 'Throttles',
+ Datapoints: [],
+ },
+ { ResponseMetadata: { RequestId: '1f50c7b1-b569-11e6-b1b6-ab86694b617b' },
+ Label: 'Errors',
+ Datapoints: [],
+ },
+ { ResponseMetadata: { RequestId: '1f63db14-b569-11e6-8501-d98a275ce164' },
+ Label: 'Duration',
+ Datapoints: [],
+ },
+ ];
+
+ return awsMetrics.getMetrics().then((result) => {
+ expect(result).to.deep.equal(expectedResult);
+ });
+ });
+ });
+
+ describe('#showMetrics()', () => {
+ let consoleLogStub;
+
+ beforeEach(() => {
+ awsMetrics.options.function = 'function1';
+ awsMetrics.options.startTime = '1970-01-01';
+ awsMetrics.options.endTime = '1970-01-02';
+ consoleLogStub = sinon.stub(serverless.cli, 'consoleLog').returns();
+ });
+
+ afterEach(() => {
+ serverless.cli.consoleLog.restore();
+ });
+
+ it('should display all metrics for the given function', () => {
+ const metrics = [
+ {
+ ResponseMetadata: {
+ RequestId: '1f50045b-b569-11e6-86c6-eb54d1aaa755',
+ },
+ Label: 'Invocations',
+ Datapoints: [{ Sum: 12 }, { Sum: 8 }],
+ },
+ {
+ ResponseMetadata: {
+ RequestId: '1f59059b-b569-11e6-aa18-c7bab68810d2',
+ },
+ Label: 'Throttles',
+ Datapoints: [{ Sum: 15 }, { Sum: 15 }],
+ },
+ {
+ ResponseMetadata: {
+ RequestId: '1f50c7b1-b569-11e6-b1b6-ab86694b617b',
+ },
+ Label: 'Errors',
+ Datapoints: [{ Sum: 0 }],
+ },
+ {
+ ResponseMetadata: {
+ RequestId: '1f63db14-b569-11e6-8501-d98a275ce164',
+ },
+ Label: 'Duration',
+ Datapoints: [{ Average: 1000 }],
+ },
+ ];
+
+ let expectedMessage = '';
+ expectedMessage += `${chalk.yellow.underline(awsMetrics.options.function)}\n`;
+ expectedMessage += 'January 1, 1970 12:00 AM - January 2, 1970 12:00 AM\n\n';
+ expectedMessage += `${chalk.yellow('Invocations: 20 \n')}`;
+ expectedMessage += `${chalk.yellow('Throttles: 30 \n')}`;
+ expectedMessage += `${chalk.yellow('Errors: 0 \n')}`;
+ expectedMessage += `${chalk.yellow('Duration (avg.): 1000ms')}`;
+
+ return awsMetrics.showMetrics(metrics).then((message) => {
+ expect(consoleLogStub.calledOnce).to.equal(true);
+ expect(message).to.equal(expectedMessage);
+ });
+ });
+
+ it('should resolve with an error message if no metrics are available', () => {
+ let expectedMessage = '';
+ expectedMessage += `${chalk.yellow.underline(awsMetrics.options.function)}\n`;
+ expectedMessage += 'January 1, 1970 12:00 AM - January 2, 1970 12:00 AM\n\n';
+ expectedMessage += `${chalk.yellow('There are no metrics to show for these options')}`;
+
+ return awsMetrics.showMetrics().then((message) => {
+ expect(consoleLogStub.calledOnce).to.equal(true);
+ expect(message).to.equal(expectedMessage);
+ });
+ });
+ });
+});
diff --git a/lib/plugins/metrics/metrics.js b/lib/plugins/metrics/metrics.js
new file mode 100644
index 000000000..3cc54bf4b
--- /dev/null
+++ b/lib/plugins/metrics/metrics.js
@@ -0,0 +1,40 @@
+'use strict';
+
+class Metrics {
+ constructor(serverless, options) {
+ this.serverless = serverless;
+ this.options = options;
+
+ this.commands = {
+ metrics: {
+ usage: 'Show metrics for a specific function',
+ lifecycleEvents: [
+ 'metrics',
+ ],
+ options: {
+ function: {
+ usage: 'The function name',
+ required: true,
+ shortcut: 'f',
+ },
+ stage: {
+ usage: 'Stage of the service',
+ shortcut: 's',
+ },
+ region: {
+ usage: 'Region of the service',
+ shortcut: 'r',
+ },
+ startTime: {
+ usage: 'Start time for the metrics retrieval (e.g. 1970-01-01)',
+ },
+ endTime: {
+ usage: 'End time for the metrics retrieval (e.g. 1970-01-01)',
+ },
+ },
+ },
+ };
+ }
+}
+
+module.exports = Metrics;
diff --git a/lib/plugins/metrics/metrics.test.js b/lib/plugins/metrics/metrics.test.js
new file mode 100644
index 000000000..7ad7afb97
--- /dev/null
+++ b/lib/plugins/metrics/metrics.test.js
@@ -0,0 +1,34 @@
+'use strict';
+
+const expect = require('chai').expect;
+const Metrics = require('./metrics');
+const Serverless = require('../../Serverless');
+
+describe('Metrics', () => {
+ let metrics;
+ let serverless;
+
+ beforeEach(() => {
+ serverless = new Serverless();
+ const options = {};
+ metrics = new Metrics(serverless, options);
+ });
+
+ describe('#constructor()', () => {
+ it('should have the command "metrics"', () => {
+ // eslint-disable-next-line no-unused-expressions
+ expect(metrics.commands.metrics).to.not.be.undefined;
+ });
+
+ it('should have a lifecycle event "metrics"', () => {
+ expect(metrics.commands.metrics.lifecycleEvents).to.deep.equal([
+ 'metrics',
+ ]);
+ });
+
+ it('should have a required option "function"', () => {
+ // eslint-disable-next-line no-unused-expressions
+ expect(metrics.commands.metrics.options.function.required).to.be.true;
+ });
+ });
+});