You are viewing the preview version of this book
Click here for the full version.

Logging and monitoring

AppSync is integrated with CloudWatch, both Logs and Metrics so it can automatically publish debugging and operational information there. And CloudWatch comes with a rich toolset to analyze and monitor this data, this makes it relatively easy to gain insight of what is happening with the API. And as CloudWatch is a managed serverless solution, you can't overwhelm it with too much data. Provided, of course, that you are willing to pay for that.

In this chapter we'll take a look into how logging and monitoring works for an AppSync API.

Logging

The primary purpose of logging is debugging, and AppSync can publish a good range of information (if configured to do so) to the logs. But, of course, there are edge cases you should be looking out for.

Setup logging

CloudWatch Logs uses a 2-layered system for logs. The top level is the Log Group which is the container for a single entity, such as an AppSync API. It's name is determined by the AppSync service: /aws/appsync/apis/<apiid>.

The lower level is the Log Streams. AppSync automatically creates these streams according to some internal logic, and they contain the actual log messages. In practice, you query the stream with the latest log message to see the most recent log events.

AppSync follows the usual AWS way in regards to permissions: the service needs an IAM role to gain write access to CloudWatch Logs as by default it has no permissions on its own.

The minimal set of permissions give write access to the groups, streams, and messages:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "*"
    }
  ]
}
Tip

Don't give logs:CreateLogGroup permission to AppSync.

If you use the Management Console, AWS creates the role with these permissions.

This is good for getting started, but if you use some Infrastructure-as-Code solution, such as CloudFormation, Terraform, or the CDK, this is not the way you want to manage logging. The problem with letting AppSync to manage the log group is that if you delete the API, the log group will still be there. And since, by default, the log messages have no expiration, you'll pay for storage even when the API is long gone.

A better solution is to create the log group with the IaC tool and don't give AppSync the logs:CreateLogGroup permission. This way, the API is still able to manage the streams and push the messages, but deleting the stack clears the logs too. And, as an extra benefit, you'll be able to define the retention too.

For example, this is how to create the log group for the AppSync API with Terraform:

resource "aws_cloudwatch_log_group" "appsync_loggroup" {
  name =  "/aws/appsync/apis/${aws_appsync_graphql_api.appsync.id}"
  retention_in_days = 14
}

Then give a limited set of permissions to the AppSync API:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "*"
    }
  ]
}
Log levels

AppSync supports various settings for what is logged. There are two controls for this:

  • Whether to include verbose content
  • What field resolvers are logged
AppSync logging settings

When both are turned off, only the time, id, duration, and the amount of tokens consumed (see the Request tokens chapter):

Without verbose content or resolver logging, very little information is included

Including verbose content adds the GraphQL query and the request/response headers:

Verbose logging includes the query, and headers

To get more insight of what is happening during a request, you can enable resolver logging. This shows which resolvers are run, and what their request templates were:

Resolver logging shows what resolvers were run during a request

Then verbose resolver logging also shows the context for each resolver. Since the context is the central part of what a resolver does, this is especially useful for debugging. Usually, it is possible to recreate what happened during an execution with this information.

Verbose resolver logging shows the value of the context
Tip

Verbose resolver logging allows visibility into what AppSync does during a request. Since GraphQL uses its own logic when it runs the resolvers it can be extremely useful.

Analyze logs

Each log entry has a request ID that makes it easy to filter log entries that belong to the same request. This is a UUID that is unique enough that it's not likely that it appears accidentally on an unrelated entry. In practice, whenever you find an entry, you can quickly switch to seeing the whole flow. Just don't forget to use "" in the search field for exact match.

Each log entry has a request ID to allow easy filtering

As these logs are available in CloudWatch Logs, you can also write complex queries to visualize various aspects of the API. This is done through CloudWatch Logs Insights, and AWS even provides some example queries, such as most invoked resolvers, slowest fields, and most errors.

CloudWatch Logs Insights allows complex queries agains AppSync logs
More ideas

For more ways to analyze logs, see this blog post.

Log costs

As we've seen, when verbose logging for all resolvers are enabled, AppSync generates a lot of messages. While it's not a scalability problem, CloudWatch bills for all these messages and the overal cost can be significant. It can even be more than the cost of the API itself.

There is more, but you've reached the end of this preview
Read this and all other chapters in full and get lifetime access to:
  • all future updates
  • full web-based access
  • PDF and Epub versions