From 41bc1b66a561a36bcc1cceca9af6c6f7dab9a1f3 Mon Sep 17 00:00:00 2001 From: julszymanski <85003886+julszymanski@users.noreply.github.com> Date: Fri, 1 Apr 2022 15:40:57 -0400 Subject: [PATCH 01/24] submission --- answers.md | 188 +++++++++++++++++- images/Alert Conditions.png | Bin 0 -> 301296 bytes images/Avg of My_Metric 5min.png | Bin 0 -> 56218 bytes images/Avg of My_Metric.png | Bin 0 -> 73215 bytes ...nomaly - Avg of PostgreSQL Connections.png | Bin 0 -> 49442 bytes images/Database + Anomaly Bonus.png | Bin 0 -> 53038 bytes images/Scope My_Metric Over Host.png | Bin 0 -> 50817 bytes images/Sum of My_Metric Points.png | Bin 0 -> 195309 bytes images/alert.png | Bin 0 -> 286799 bytes images/alert_message.png | Bin 0 -> 111733 bytes images/anomaly.png | Bin 0 -> 63819 bytes images/custom_my_metric.png | Bin 0 -> 199085 bytes images/dashboard.png | Bin 0 -> 553179 bytes images/dive.gif | Bin 0 -> 992719 bytes images/dockerlog.png | Bin 0 -> 185798 bytes images/dockermetrics.png | Bin 0 -> 255217 bytes images/downtime.png | Bin 0 -> 656181 bytes images/email.png | Bin 0 -> 1382702 bytes images/graphs_hour.png | Bin 0 -> 523100 bytes images/hostmap.png | Bin 0 -> 76627 bytes images/message.png | Bin 0 -> 503681 bytes images/my_metric.png | Bin 0 -> 402167 bytes images/my_metric_conf.png | Bin 0 -> 33421 bytes images/my_service dash.png | Bin 0 -> 1751444 bytes images/my_service.png | Bin 0 -> 130994 bytes images/notification.png | Bin 0 -> 1072252 bytes images/notify.png | Bin 0 -> 82736 bytes images/postgres.png | Bin 0 -> 264036 bytes images/postgres_integration.png | Bin 0 -> 23916 bytes images/postgreserror.png | Bin 0 -> 149930 bytes images/rollup.png | Bin 0 -> 61677 bytes images/snapshot.png | Bin 0 -> 399347 bytes images/solution.png | Bin 0 -> 318479 bytes images/tags.png | Bin 0 -> 131147 bytes images/timeboard.png | Bin 0 -> 378612 bytes images/warning.png | Bin 0 -> 493165 bytes images/weekday.png | Bin 0 -> 386264 bytes images/weekend.png | Bin 0 -> 366718 bytes images/weekend_downtime.png | Bin 0 -> 648258 bytes images/whale.gif | Bin 0 -> 615757 bytes my_app.py | 28 +++ 41 files changed, 215 insertions(+), 1 deletion(-) create mode 100644 images/Alert Conditions.png create mode 100644 images/Avg of My_Metric 5min.png create mode 100644 images/Avg of My_Metric.png create mode 100644 images/Database + Anomaly - Avg of PostgreSQL Connections.png create mode 100644 images/Database + Anomaly Bonus.png create mode 100644 images/Scope My_Metric Over Host.png create mode 100644 images/Sum of My_Metric Points.png create mode 100644 images/alert.png create mode 100644 images/alert_message.png create mode 100644 images/anomaly.png create mode 100644 images/custom_my_metric.png create mode 100644 images/dashboard.png create mode 100644 images/dive.gif create mode 100644 images/dockerlog.png create mode 100644 images/dockermetrics.png create mode 100644 images/downtime.png create mode 100644 images/email.png create mode 100644 images/graphs_hour.png create mode 100644 images/hostmap.png create mode 100644 images/message.png create mode 100644 images/my_metric.png create mode 100644 images/my_metric_conf.png create mode 100644 images/my_service dash.png create mode 100644 images/my_service.png create mode 100644 images/notification.png create mode 100644 images/notify.png create mode 100644 images/postgres.png create mode 100644 images/postgres_integration.png create mode 100644 images/postgreserror.png create mode 100644 images/rollup.png create mode 100644 images/snapshot.png create mode 100644 images/solution.png create mode 100644 images/tags.png create mode 100644 images/timeboard.png create mode 100644 images/warning.png create mode 100644 images/weekday.png create mode 100644 images/weekend.png create mode 100644 images/weekend_downtime.png create mode 100644 images/whale.gif create mode 100644 my_app.py diff --git a/answers.md b/answers.md index 092b6d280..3adff7300 100644 --- a/answers.md +++ b/answers.md @@ -1 +1,187 @@ -Your answers to the questions go here. +

Julia Szymanski Datadog Technical Assessment

+ +

Notes on Prerequisites:

+

I took this assessment as a great opportunity to learn about Docker and opted for the Containerized approach using Docker for Desktop (Mac M1) and the dockerized Datadog agent.

+ + +docker gif + + +

Collecting Metrics:

+

1. I added tags in the datadog.yaml file and verified they were in the Host Map.

+ + +tags code + +

+ +drawing + +

+

2. I installed PostgreSQL on my machine and installed the PostgreSQL Datadog integration. +

+ +At first, this is the error I was seeing in the root terminal and dd-agent log:

+

+ +drawing + +

+

+ +Docker log + +

+ +

The issue was that I had set host to localhost in postgres.d/conf.yaml, but the host has a changing IP address. I reset host to host.docker.internal. This enabled the connection of the container with the db service on the host by forwarding to the internal IP address used by the host.

+

Click here to see the docs --> Networking features in Docker Desktop for Mac

+ +Postgres connection + +Postgres Integration + +

3. I created a custom Agent check that submits a metric named my_metric with a random value between 0 and 1000.

+ + +my_metric check + +my_metric check + + + +

4. I changed my check's collection interval so that it only submits the metric once every 45 seconds by modifying the respective yaml file.

+ + +my_metric_conf + + +

Bonus Question: By modifying conf.yaml that lives in the conf folder, I did change the collection interval without modifying custom_my_metric.py.

+ +

Visualizing Data:

+ +

I created an Application Key and verified that the App Key and the API Key are valid via Postman. Then I wrote the script for a timeboard importing the Datadog API.

+ + +timeboard +

Script I used to create the timeboard

+

+ +

I scoped My_Metric over my host.

+my_metric scoped over host +avg my_metric + + +

2. I applied an anomaly function using the postgres.connections metric as an argument.

+ +anomaly +Database + Anomaly - Avg of PostgreSQL Connections + +

3. The rollup function is used to aggregate metrics data. The two arguments passed to the rollup function are the aggregator (min, max, in this case sum) and the optional time interval. In my rollup function, I sum all my_metric values collected in the last hour. In the graph below, the sum value is 28.71K. Dividing this number by our min_collection_interval value of 45 seconds, the average my_metric value for that hour came out to be 359. +

+ +rollup +rollup + +Avg of My_Metric 5min +

4. I set the Timboard's timeframe to the past 5 minutes.

+snapshot + +

5. I took a snapshot of the graph and used the @ notation to email it to myself. 📧

+ +

+ + +

Bonus Question: +Anomaly detection is an algorithmic feature that identifies when a metric is behaving differently than it has in the past. A metric is considered to be anomalous (deviating from what is standard, normal, or expected) if it is outside of the gray anomaly band in the anomaly graph.

+ +Database + Anomaly Bonus + + +

Monitoring Data:

+ +

1. I created a new Metric Monitor that watches the average of my_metric and will alert if it's above the following values over the past 5 min: + +• Warning threshold of 500 +• Alerting threshold of 800 +• And also ensure that it will notify me if there is No Data for this query over the past 10m.

+ +Alert Conditions + +notify +

2. I set the monitor to send me an email whenenever it is triggered.

+message +

3. I created different messages based on whether the monitor is in an Alert, Warning, or No Data state.

+alert message +

4. I included the metric value that caused the monitor to trigger and host name and ip when the monitor triggers an Alert state.

+ +email +

5. Here is a screenshot of an email notification for the Alert state sent by the monitor.

+ + +

Bonus question: I set up two scheduled downtimes for this monitor.

+ +downtime +weekday + +

1. I silenced the monitor from 7pm to 9am daily Monday-Friday. 💤

+

+ +

+weekend downtime +weekend +

2. I also silenced the monitor all day on Saturday and Sunday. 🌴 🏄 🏖️

+

+ +notification +

3. 📧 My email was notified when I scheduled the downtime.

+ + +

Collecting APM Data:

+ +

Bonus Question: Difference between a Service and a Resource +

+

Referred to APM Glossary & Walkthrough

+ +

+Services are the building blocks of modern microservice architectures - broadly a service groups together endpoints, queries, or jobs for the purposes of building your application. For example, a database service groups resources such as database queries. Resources belong to services. +

+Resources are actions for your services representing a particular domain of a customer application - they are typically an instrumented web endpoint, database query, or background job.

+ +

+

You can view trace metrics on a service's Service page to see the performance of every resource such as a web endpoint or database query belonging to the service. Each resource has its own Resource page with trace metrics scoped to the specific endpoint.

+ +dashboard + +

Note: See fully instrumented app my_app.py.

+ +Click here to see Integrations + APM Dashboard + +

Final Question:

+ +

Datadog has been used in a lot of creative ways in the past. We’ve written some blog posts about using Datadog to monitor the NYC Subway System, Pokemon Go, and even office restroom availability! + +Is there anything creative you would use Datadog for?

+ +

When I first moved to Atlanta, I moved into an older home with a rodent problem. I measured rodent activity in the house by making mental notes of the frequency of the scuttling sounds in the ceilings and walls. It would be interesting to place a sensor with a scanner in my home to monitor where rodent activity is the highest. I can integrate the sensor with Datadog to monitor rodent activity at different points in the house. The next time I hire Critter Stoppers, they could use these metrics to place traps in the rooms or areas with the highest measured rodent activity. I can be alerted by anomaly detection if rodent activity drops, meaning that the exterminator did a great job.

+ + + + + + + + + + + + + + + + + + + + + diff --git a/images/Alert Conditions.png b/images/Alert Conditions.png new file mode 100644 index 0000000000000000000000000000000000000000..ea66f8f78c4d24053a596f8955c5890d24fbd0ac GIT binary patch literal 301296 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