Anthony Bloomer
Posted on July 19, 2020
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, 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 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.
How it works
As a starting point, I developed a small Python client 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:
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 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:
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:
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:
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 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.
pip install -r requirements.txt
Export your Personal API Key as an environment variable.
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:
export NEW_RELIC_REGION = "EU"
Edit config.py
with the New Relic Dashboard and Email settings.
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 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 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.
Posted on July 19, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.