Periodically share a New Relic Dashboard using the GMail API
Tags: python, newrelic, gmailapi
Published: 2020-07-19 16:45:03

## Overview 

A common request I have received from customers is the ability to create performance reports to share with other members of their team or to their clients. While New Relic does provide email [weekly performance reports](https://docs.newrelic.com/docs/apm/reports), it is often the case that customers wish to email custom reports with the performance and business metrics they care about most.

With the [New Relic NerdGraph](https://docs.newrelic.com/docs/apis/nerdgraph/get-started/introduction-new-relic-nerdgraph) API, it is now possible to retrieve the link for the current snapshot of your New Relic Dashboard! This opens up a lot of programmable capabilities for our customers. One use-case would be to programmatically generate a snapshot of a performance dashboard that could be mailed every week.

Given this new functionality, I worked on a project to periodically share a New Relic Dashboard using the [GMail API](https://developers.google.com/gmail/api).

## How it works

As a starting point, I developed a small [Python client](https://pypi.org/project/nrde/) that abstracts the API call made to the NerdGraph API. The client retrieves the latest snapshot URL for a given dashboard and then downloads that file: 

``` python
def exporter(
    guid: str,
    file_type: str = "PDF",
    output_directory: str = os.getcwd(),
    filename: str = int(time.time()),
    width: int = 2000,
    height: int = 2000,
):
    if not os.getenv("NEW_RELIC_PERSONAL_API_KEY"):
        sys.exit("New Relic API key and region environment variables required.")
    headers = {
        "Content-Type": "application/json",
        "API-Key": os.getenv("NEW_RELIC_PERSONAL_API_KEY"),
    }
    endpoint_url = (
        "https://api.eu.newrelic.com/graphql"
        if os.getenv("NEW_RELIC_REGION") == "EU"
        else "https://api.newrelic.com/graphql"
    )
    if not guid or not guid.strip():
        sys.exit("Dashboard GUID required.")
    query = '''
    mutation {
        dashboardCreateSnapshotUrl(guid: "%s")
    }
    ''' % guid
    req = requests.post(url=endpoint_url, json={"query": query}, headers=headers)

    if not req.ok:
        req.raise_for_status()
    resp = req.json()
    url = resp["data"]["dashboardCreateSnapshotUrl"]
    if url is None:
        sys.exit("Dashboard not found.")
    url = url.split("?", 1)[0] + "?format=%s&width=%s&height=%s" % (
        file_type,
        width,
        height,
    )
    resp = requests.get(url=url)
    content_type = resp.headers["content-type"]
    extension = mimetypes.guess_extension(content_type)
    of = "%s/%s%s" % (output_directory, filename, extension)
    with open(of, "wb") as f:
        f.write(resp.content)
        f.close()
    return of
```

Next, I wrote some code to interact with the GMail API. Google provides a [client library for Python](https://github.com/googleapis/google-api-python-client) that simplifies a lot of the process involved with things like API authorization and sending emails. 

The process is to first authorize the application to allow the API to perform actions on behalf of the user. Once a token has been generated, the GMail API handles token refreshes so initial authorization only needs to be done once:

``` python
def get_service():
    scopes = "https://mail.google.com/"
    credentials = None
    if os.path.exists("token.pickle"):
        with open("token.pickle", "rb") as token:
            credentials = pickle.load(token)
    if not credentials or not credentials.valid:
        if credentials and credentials.expired and credentials.refresh_token:
            credentials.refresh(Request())
        else:
            flow = InstalledAppFlow.from_client_secrets_file("credentials.json", scopes)
            credentials = flow.run_local_server(port=0)
        with open("token.pickle", "wb") as token:
            pickle.dump(credentials, token)

    service = build("gmail", "v1", credentials=credentials)
    return service
```

Once the user has authorized the application, it is then easy to perform actions on their behalf:

``` python
def send_email(session, user_id, message):
    k = session.users().messages().send(userId=user_id, body=message).execute()
    print("Message Id: %s" % k["id"])
    return k
```

The final step of this project was to write a script to periodically download the latest dashboard image and send it is an email:

``` python
def job():
    print("Exporting New Relic dashboard...")
    dashboard = exporter(
        guid=config["dashboard"]["guid"],
        file_type=config["dashboard"]["file_type"],
        width=int(config["dashboard"]["width"]),
        height=int(config["dashboard"]["height"]),
    )
    print("Creating message...")
    message = create_message_with_attachment(
        sender=config["email"]["sender"],
        to=config["email"]["to"],
        subject=config["email"]["subject"],
        message_text=config["email"]["text"],
        file=dashboard,
    )
    print("Authenticating with Google...")
    service = get_service()
    print("Sending email...")
    send_email(message=message, user_id="me", session=service)
    print("Done!")

if __name__ == "__main__":
    # Run the initial job to authenticate with Google.
    job()
    schedule.every().friday.do(job)
```

Check the installation instructions below if you'd like to test this project out! :) 

## Installation

Clone the [Github repository](https://github.com/AnthonyBloomer/dashboard-email-scheduler/) and set up a virtual environment.

```
git clone https://github.com/AnthonyBloomer/dashboard-email-scheduler.git
cd dashboard-email-scheduler
virtualenv env
source env/bin/activate
```

Install the project requirements.

``` shell
pip install -r requirements.txt
```

Export your [Personal API Key](https://docs.newrelic.com/docs/apis/get-started/intro-apis/types-new-relic-api-keys#personal-api-key) as an environment variable.

``` shell
export NEW_RELIC_PERSONAL_API_KEY = "YOUR_API_KEY"
```

If you have an EU based account, you will also need to export the `NEW_RELIC_REGION` environment variable:

``` shell
export NEW_RELIC_REGION = "EU"
```

Edit `config.py` with the New Relic Dashboard and Email settings.

``` python
config = {
    "email": {
        "sender": "Email sender.",
        "to": "Email receiver.",
        "subject": "Email subject",
        "text": "Email message text",
    },
    "dashboard": {
        "guid": "The New Relic Dashboard GUID",
        "file_type": "PDF",
        "width": "2000",
        "height": "2000",
    },
}
```

Go to the [Google Developer Console](https://console.developers.google.com/?pli=1) and create a new project. Once the API is enabled, download the `credentials.json` file to the root directory of this project.

Run `python scheduler.py`. This will run an initial job so you can authenticate the application. By default, the job will run every Friday. Refer to the [Schedule](https://pypi.org/project/schedule/) project documentation to configure the scheduler to your liking. 

If you've made it this far, thanks for reading! :D I hope you find this project useful.