diff --git a/samcli/cli/options.py b/samcli/cli/options.py index f686ed0a3a..c5e7baaff5 100644 --- a/samcli/cli/options.py +++ b/samcli/cli/options.py @@ -23,7 +23,7 @@ def callback(ctx, param, value): expose_value=False, is_flag=True, envvar="SAM_DEBUG", - help='Turn on debug logging', + help='Turn on debug logging to print debug message generated by SAM CLI.', callback=callback)(f) @@ -40,7 +40,7 @@ def callback(ctx, param, value): return click.option('--region', expose_value=False, - help='Set the AWS Region of the service', + help='Set the AWS Region of the service (e.g. us-east-1).', callback=callback)(f) @@ -57,5 +57,5 @@ def callback(ctx, param, value): return click.option('--profile', expose_value=False, - help='Select a specific profile from your credential file to get AWS credentials', + help='Select a specific profile from your credential file to get AWS credentials.', callback=callback)(f) diff --git a/samcli/commands/local/cli_common/options.py b/samcli/commands/local/cli_common/options.py index 42b4225bbe..0a1cb9724e 100644 --- a/samcli/commands/local/cli_common/options.py +++ b/samcli/commands/local/cli_common/options.py @@ -109,7 +109,7 @@ def invoke_common_options(f): envvar="SAM_DEBUG_PORT"), click.option('--debug-args', - help="Additional arguments to be passed to the debugger", + help="Additional arguments to be passed to the debugger.", envvar="DEBUGGER_ARGS"), click.option('--docker-volume-basedir', '-v', @@ -120,16 +120,16 @@ def invoke_common_options(f): click.option('--docker-network', envvar="SAM_DOCKER_NETWORK", - help="Specifies the name or id of an existing docker network to lambda docker" - "containers should connect to, along with the default bridge network. If not specified," + help="Specifies the name or id of an existing docker network to lambda docker " + "containers should connect to, along with the default bridge network. If not specified, " "the Lambda containers will only connect to the default bridge docker network."), click.option('--log-file', '-l', - help="logfile to send runtime logs to"), + help="logfile to send runtime logs to."), click.option('--skip-pull-image', is_flag=True, - help="Specify whether CLI should skip pulling down the latest Docker image for Lambda runtime", + help="Specify whether CLI should skip pulling down the latest Docker image for Lambda runtime.", envvar="SAM_SKIP_PULL_IMAGE"), click.option('--profile', diff --git a/samcli/commands/local/generate_event/cli.py b/samcli/commands/local/generate_event/cli.py index f99691c6fc..cd2c329bff 100644 --- a/samcli/commands/local/generate_event/cli.py +++ b/samcli/commands/local/generate_event/cli.py @@ -13,20 +13,20 @@ HELP_TEXT = """ -Generate a Lambda Event that can be used to invoke a Lambda Function. - -Useful for developing serverless functions that handle asynchronous events (such as S3/Kinesis etc), or if you want to -compose a script of test cases. Event body can be passed in either by stdin (default), or by using the --event -parameter. Runtime output (logs etc) will be outputted to stderr, and the Lambda function result will be outputted to -stdout. +You can use this command to generate sample payloads from different event sources +such as S3, API Gateway, and SNS. These payloads contain the information that the +event sources send to your Lambda functions.\n +\b +Generate the event that S3 sends to your Lambda function when a new object is uploaded +$ sam local generate-event s3 --bucket --key \n +\b +After you generate a sample event, you can use it to test your Lambda function locally +$ sam local generate-event s3 --bucket --key | sam local invoke """ -@click.group("generate-event") +@click.group("generate-event", help=HELP_TEXT) def cli(): - """ - Generate an event - """ pass # pragma: no cover diff --git a/samcli/commands/local/invoke/cli.py b/samcli/commands/local/invoke/cli.py index 26e8e34dab..85e178842d 100644 --- a/samcli/commands/local/invoke/cli.py +++ b/samcli/commands/local/invoke/cli.py @@ -16,16 +16,19 @@ HELP_TEXT = """ -Invokes a local Lambda function once and quits after invocation completes. - -Useful for developing serverless functions that handle asynchronous events (such as S3/Kinesis etc), or if you want to -compose a script of test cases. Event body can be passed in either by stdin (default), or by using the --event -parameter. Runtime output (logs etc) will be outputted to stderr, and the Lambda function result will be outputted to -stdout. +You can use this command to execute your function in a Lambda-like environment locally. +You can pass in the event body via stdin or by using the -e (--event) parameter. +Logs from the Lambda function will be output via stdout.\n +\b +Invoking a Lambda function using an event file +$ sam local invoke "HelloWorldFunction" -e event.json\n +\b +Invoking a Lambda function using input from stdin +$ echo '{"message": "Hey, are you there?" }' | sam local invoke "HelloWorldFunction" \n """ -@click.command("invoke", help=HELP_TEXT, short_help="Invokes a local Lambda function once") +@click.command("invoke", help=HELP_TEXT, short_help="Invokes a local Lambda function once.") @click.option("--event", '-e', type=click.Path(), default="-", # Defaults to stdin diff --git a/samcli/commands/local/start_api/cli.py b/samcli/commands/local/start_api/cli.py index d50c34cd96..04b9c68f31 100644 --- a/samcli/commands/local/start_api/cli.py +++ b/samcli/commands/local/start_api/cli.py @@ -28,7 +28,10 @@ """ -@click.command("start-api", help=HELP_TEXT, short_help="Runs your APIs locally") +@click.command("start-api", + help=HELP_TEXT, + short_help="Sets up a local endpoint you can use to test your API. Supports hot-reloading " + "so you don't need to restart this service when you make changes to your function.") @service_common_options(3000) @click.option("--static-dir", "-s", default="public", diff --git a/samcli/commands/local/start_lambda/cli.py b/samcli/commands/local/start_lambda/cli.py index 97064a3c1e..1466f48ac2 100644 --- a/samcli/commands/local/start_lambda/cli.py +++ b/samcli/commands/local/start_lambda/cli.py @@ -15,20 +15,40 @@ LOG = logging.getLogger(__name__) HELP_TEXT = """ -Allows you to run a Local Lambda Service that will service the invoke path to your functions for quick development & - testing through the AWS CLI or SDKs. When run in a directory that contains your Serverless functions and your AWS - SAM template, it will create a local HTTP server that wil response to the invoke call to your functions. - When accessed (via browser, cli etc), it will launch a Docker container locally to invoke the function. It will read - the CodeUri property of AWS::Serverless::Function resource to find the path in your file system containing the Lambda - Function code. This could be the project's root directory for interpreted languages like Node & Python, or a build - directory that stores your compiled artifacts or a JAR file. If you are using a interpreted language, local changes - will be available immediately in Docker container on every invoke. For more compiled languages or projects requiring - complex packing support, we recommended you run your own building solution and point SAM to the directory or file - containing build artifacts. +You can use this command to programmatically invoke your Lambda function locally using the AWS CLI or SDKs. +This command starts a local endpoint that emulates the AWS Lambda service, and you can run your automated +tests against this local Lambda endpoint. When you send an invoke to this endpoint using the AWS CLI or +SDK, it will locally execute the Lambda function specified in the request.\n +\b +SETUP +------ +Start the local Lambda endpoint by running this command in the directory that contains your AWS SAM template. +$ sam local start-lambda\n +\b +USING AWS CLI +------------- +Then, you can invoke your Lambda function locally using the AWS CLI +$ aws lambda invoke --function-name "HelloWorldFunction" --endpoint-url "http://127.0.0.1:3001" --no-verify-ssl out.txt +\n +\b +USING AWS SDK +------------- +You can also use the AWS SDK in your automated tests to invoke your functions programatically. +Here is a Python example: + self.lambda_client = boto3.client('lambda', + endpoint_url="http://127.0.0.1:3001", + use_ssl=False, + verify=False, + config=Config(signature_version=UNSIGNED, + read_timeout=0, + retries={'max_attempts': 0})) + self.lambda_client.invoke(FunctionName="HelloWorldFunction") """ -@click.command("start-lambda", help=HELP_TEXT, short_help="Runs a Local Lambda Service (for the Invoke path only)") +@click.command("start-lambda", + help=HELP_TEXT, + short_help="Starts a local endpoint you can use to invoke your local Lambda functions.") @service_common_options(3001) @invoke_common_options @cli_framework_options diff --git a/samcli/commands/logs/command.py b/samcli/commands/logs/command.py index 8572d3d2dc..fa4f785219 100644 --- a/samcli/commands/logs/command.py +++ b/samcli/commands/logs/command.py @@ -11,40 +11,57 @@ LOG = logging.getLogger(__name__) HELP_TEXT = """ -Use this command to fetch logs printed by your Lambda function. +Use this command to fetch logs generated by your Lambda function.\n +\b +When your functions are a part of a CloudFormation stack, you can fetch logs using the function's +LogicalID when you specify the stack name. +$ sam logs -n HelloWorldFunction --stack-name mystack \n +\b +Or, you can fetch logs using the function's name. +$ sam logs -n mystack-HelloWorldFunction-1FJ8PD36GML2Q \n +\b +You can view logs for a specific time range using the -s (--start-time) and -e (--end-time) options +$ sam logs -n HelloWorldFunction --stack-name mystack -s '10min ago' -e '2min ago' \n +\b +You can also add the --tail option to wait for new logs and see them as they arrive. +$ sam logs -n HelloWorldFunction --stack-name mystack --tail \n +\b +Use the --filter option to quickly find logs that match terms, phrases or values in your log events. +$ sam logs -n HelloWorldFunction --stack-name mystack --filter "error" \n """ @click.command("logs", help=HELP_TEXT, short_help="Fetch logs for a function") -@click.option("--function", "-f", +@click.option("--name", "-n", required=True, - help="Name of the AWS Lambda function. If this function is a part of SAM stack, this can" - "be the LogicalID of function resource in SAM template") + help="Name of your AWS Lambda function. If this function is a part of a CloudFormation stack, " + "this can be the LogicalID of function resource in the CloudFormation/SAM template.") @click.option("--stack-name", default=None, - help="Name of AWS CloudFormation stack that the function is a part of") + help="Name of the AWS CloudFormation stack that the function is a part of.") @click.option("--filter", default=None, - help="Filter logs using this expression. It could be a simple keyword or a complex pattern that is" - "supported by AWS CloudWatch Logs. See AWS CloudWatch Logs documentation for pattern syntax - " + help="You can specify an expression to quickly find logs that match terms, phrases or values in " + "your log events. This could be a simple keyword (e.g. \"error\") or a pattern " + "supported by AWS CloudWatch Logs. See the AWS CloudWatch Logs documentation for the syntax " "https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/FilterAndPatternSyntax.html") -@click.option("--tail", "-t", - is_flag=True, - help="Tail the log output. This will ignore the end time argument and continue to fetch logs as they" - "become available") @click.option("--start-time", "-s", default='10m ago', - help="Fetch logs starting at this time. Time can be relative values like '5 mins ago', 'tomorrow' or " - "formatted timestamp like '2017-01-01 10:10:10'") + help="Fetch logs starting at this time. Time can be relative values like '5mins ago', 'yesterday' or " + "formatted timestamp like '2018-01-01 10:10:10'. Defaults to '10mins ago'.") @click.option("--end-time", "-e", default=None, - help="Fetch logs up to this time. Time can be relative values like '5 mins ago', 'tomorrow' or " - "formatted timestamp like '2017-01-01 10:10:10'") + help="Fetch logs up to this time. Time can be relative values like '5mins ago', 'tomorrow' or " + "formatted timestamp like '2018-01-01 10:10:10'") +@click.option("--tail", "-t", + is_flag=True, + help="Tail the log output. This will ignore the end time argument and continue to fetch logs as they " + "become available.") @cli_framework_options @aws_creds_options @pass_context def cli(ctx, - function, # pylint: disable=redefined-builtin + name, stack_name, filter, # pylint: disable=redefined-builtin tail, @@ -53,7 +70,7 @@ def cli(ctx, ): # All logic must be implemented in the ``do_cli`` method. This helps with easy unit testing - do_cli(function, stack_name, filter, tail, start_time, end_time) # pragma: no cover + do_cli(name, stack_name, filter, tail, start_time, end_time) # pragma: no cover def do_cli(function_name, stack_name, filter_pattern, tailing, start_time, end_time): diff --git a/samcli/commands/logs/logs_context.py b/samcli/commands/logs/logs_context.py index c101b60ca5..31bad78511 100644 --- a/samcli/commands/logs/logs_context.py +++ b/samcli/commands/logs/logs_context.py @@ -109,7 +109,6 @@ def formatter(self): LogsFormatter """ formatter_chain = [ - LambdaLogMsgFormatters.colorize_reports, LambdaLogMsgFormatters.colorize_errors, # Format JSON "before" highlighting the keywords. Otherwise, JSON will be invalid from all the diff --git a/samcli/lib/logs/formatter.py b/samcli/lib/logs/formatter.py index 7d6bdd3e3b..0c8cd2f9d3 100644 --- a/samcli/lib/logs/formatter.py +++ b/samcli/lib/logs/formatter.py @@ -145,18 +145,6 @@ def colorize_errors(event, colored): return event - @staticmethod - def colorize_reports(event, colored): - """ - AWS Lambda emits special log statements when the function starts and ends. This formatter will highlight - these statements - """ - - if event.message.startswith("START") or event.message.startswith("END") or event.message.startswith("REPORT"): - event.message = colored.white(event.message) - - return event - class KeywordHighlighter(object): """ diff --git a/tests/unit/lib/logs/test_formatter.py b/tests/unit/lib/logs/test_formatter.py index 2e8bd60876..23095f1983 100644 --- a/tests/unit/lib/logs/test_formatter.py +++ b/tests/unit/lib/logs/test_formatter.py @@ -125,38 +125,6 @@ def test_must_ignore_other_messages(self): colored.red.assert_not_called() -class TestLambdaLogMsgFormatters_colorize_reports(TestCase): - - @parameterized.expand([ - "START something", - "END something else", - "REPORT some other thing" - ]) - def test_must_color_lines_starting_with_keywords(self, input_msg): - color_result = "colored messaage" - colored = Mock() - colored.white.return_value = color_result - event = LogEvent("group_name", {"message": input_msg}) - - result = LambdaLogMsgFormatters.colorize_reports(event, colored) - self.assertEquals(result.message, color_result) - colored.white.assert_called_with(input_msg) - - @parameterized.expand([ - "something START", - "something else END", - "some other REPORT thing", - "foo bar" - ]) - def test_must_ignore_other_messages(self, input_msg): - colored = Mock() - event = LogEvent("group_name", {"message": input_msg}) - - result = LambdaLogMsgFormatters.colorize_reports(event, colored) - self.assertEquals(result.message, input_msg) - colored.white.assert_not_called() - - class TestKeywordHighlight_highlight_keyword(TestCase): def test_must_highlight_all_keywords(self):