Course
This procedure is a part of a course that teaches you how to build a quickstart. If you haven't already, checkout the course introduction.
Each procedure in this course builds on top of the last one, so make sure you deploy your application before proceeding with this one.
Metrics are aggregated measurements derived from the system’s performance and behaviors. If your product is a database, you might send metrics like CPU utilization, memory utilization, and query throughput. Note that metrics are generally only used if you want to limit the amount of Data sent to New Relic. Note that many metrics, such as error rates and throughput, can be computed by aggregating events.
New Relic provides you a variety of ways to instrument your application to send metrics to our Metric API. In this lesson, you send metrics from your product using our telemetry software development kit (SDK).
Use our SDK
We offer an open source telemetry SDK in several of the most popular programming languages. These send data to our data ingest APIs, including our Metric API. Of these language SDKs, Python, Java, Node/TypeScript, and Go work with the Metric API.
In this lesson, you learn how to install and use the Python telemetry SDK to send metrics to New Relic.
Change to the send-metrics/flashDB direcrory of the course repository.
$cd ../send-metrics/flashDB
Use pip
to install the newrelic-telemetry-sdk
package.
$pip install newrelic-telemetry-sdk
Store your New Relic license key in an environment variable called $NEW_RELIC_LICENSE_KEY.
$export NEW_RELIC_LICENSE_KEY=<USER'S LICENSE KEY>
Next, you familiarize yourself with the app logic.
Familiarize yourself with the application
Open db.py file in the IDE of your choice and familiarize yourself with the app logic.
This demo uses a dummy Python application that mimics the Create, Read, Update, and Delete (CRUD) operations.
1import os2import random3import datetime4
5db = {}6stats = {7 "read_response_times": [],8 "read_errors": 0,9 "read_count": 0,10 "create_response_times": [],11 "create_errors": 0,12 "create_count": 0,13 "update_response_times": [],14 "update_errors": 0,15 "update_count": 0,16 "delete_response_times": [],17 "delete_errors": 0,18 "delete_count": 0,19 "cache_hit": 0,20}21last_push = {22 "read": datetime.datetime.now(),23 "create": datetime.datetime.now(),24 "update": datetime.datetime.now(),25 "delete": datetime.datetime.now(),26}27
28def read(key):29
30 print(f"Reading...")31
32 if random.randint(0, 30) > 10:33 stats["cache_hit"] += 134
35 stats["read_response_times"].append(random.uniform(0.5, 1.0))36 if random.choice([True, False]):37 stats["read_errors"] += 138 stats["read_count"] += 139 try_send("read")40
41def create(key, value):42
43 print(f"Writing...")44
45 db[key] = value46 stats["create_response_times"].append(random.uniform(0.5, 1.0))47 if random.choice([True, False]):48 stats["create_errors"] += 149 stats["create_count"] += 150 try_send("create")51
52def update(key, value):53
54 print(f"Updating...")55
56 db[key] = value57 stats["update_response_times"].append(random.uniform(0.5, 1.0))58 if random.choice([True, False]):59 stats["update_errors"] += 160 stats["update_count"] += 161 try_send("update")62
63def delete(key):64
65 print(f"Deleting...")66
67 db.pop(key, None)68 stats["delete_response_times"].append(random.uniform(0.5, 1.0))69 if random.choice([True, False]):70 stats["delete_errors"] += 171 stats["delete_count"] += 172 try_send("delete")73
74def try_send(type_):75
76 print("try_send")77
78def clear(type_):79 stats[f"{type_}_response_times"] = []80 stats[f"{type_}_errors"] = 081 stats["cache_hit"] = 082 stats[f"{type_}_count"] = 083 last_push[type_] = datetime.datetime.now()
The read
, create
, update
, and delete
are the dummy methods to mimic CRUD operations. For every CRUD operations, respective stat
is incremented to reflect that the operation has been performed. Next, you send this stats
data to New Relic.
Send metrics to New Relic
There are 3 different types of metrics:
- GaugeMetric: sends a single value at a single point in time.
- CountMetric: tracks the total number of occurrences of an event.
- SummaryMetric: tracks count, sum, min, and max values over time.
Next, instrument your application to send these metrics.
In db.py, configure the MetricClient
.
1import os2import random3import datetime4
5from newrelic_telemetry_sdk import MetricClient6
7metric_client = MetricClient(os.environ["NEW_RELIC_LICENSE_KEY"])8
9db = {}10stats = {11 "read_response_times": [],12 "read_errors": 0,13 "read_count": 0,14 "create_response_times": [],15 "create_errors": 0,16 "create_count": 0,17 "update_response_times": [],18 "update_errors": 0,19 "update_count": 0,20 "delete_response_times": [],21 "delete_errors": 0,22 "delete_count": 0,23 "cache_hit": 0,24}25last_push = {26 "read": datetime.datetime.now(),27 "create": datetime.datetime.now(),28 "update": datetime.datetime.now(),29 "delete": datetime.datetime.now(),30}31
32def read(key):33
34 print(f"Reading...")35
36 if random.randint(0, 30) > 10:37 stats["cache_hit"] += 138
39 stats["read_response_times"].append(random.uniform(0.5, 1.0))40 if random.choice([True, False]):41 stats["read_errors"] += 142 stats["read_count"] += 143 try_send("read")44
45def create(key, value):46
47 print(f"Writing...")48
49 db[key] = value50 stats["create_response_times"].append(random.uniform(0.5, 1.0))51 if random.choice([True, False]):52 stats["create_errors"] += 153 stats["create_count"] += 154 try_send("create")55
56def update(key, value):57
58 print(f"Updating...")59
60 db[key] = value61 stats["update_response_times"].append(random.uniform(0.5, 1.0))62 if random.choice([True, False]):63 stats["update_errors"] += 164 stats["update_count"] += 165 try_send("update")66
67def delete(key):68
69 print(f"Deleting...")70
71 db.pop(key, None)72 stats["delete_response_times"].append(random.uniform(0.5, 1.0))73 if random.choice([True, False]):74 stats["delete_errors"] += 175 stats["delete_count"] += 176 try_send("delete")77
78def try_send(type_):79
80 print("try_send")81
82def clear(type_):83 stats[f"{type_}_response_times"] = []84 stats[f"{type_}_errors"] = 085 stats["cache_hit"] = 086 stats[f"{type_}_count"] = 087 last_push[type_] = datetime.datetime.now()
Instrument your app to send the folloiwng metrics to New Relic:
- keys
- db_size
- errors
- cache_hits
- response_times
1import os2import random3import datetime4from sys import getsizeof5
6from newrelic_telemetry_sdk import MetricClient, GaugeMetric, CountMetric, SummaryMetric7
8metric_client = MetricClient(os.environ["NEW_RELIC_LICENSE_KEY"])9
10db = {}11stats = {12 "read_response_times": [],13 "read_errors": 0,14 "read_count": 0,15 "create_response_times": [],16 "create_errors": 0,17 "create_count": 0,18 "update_response_times": [],19 "update_errors": 0,20 "update_count": 0,21 "delete_response_times": [],22 "delete_errors": 0,23 "delete_count": 0,24 "cache_hit": 0,25}26last_push = {27 "read": datetime.datetime.now(),28 "create": datetime.datetime.now(),29 "update": datetime.datetime.now(),30 "delete": datetime.datetime.now(),31}32
33def read(key):34
35 print(f"Reading...")36
37 if random.randint(0, 30) > 10:38 stats["cache_hit"] += 139
40 stats["read_response_times"].append(random.uniform(0.5, 1.0))41 if random.choice([True, False]):42 stats["read_errors"] += 143 stats["read_count"] += 144 try_send("read")45
46def create(key, value):47
48 print(f"Writing...")49
50 db[key] = value51 stats["create_response_times"].append(random.uniform(0.5, 1.0))52 if random.choice([True, False]):53 stats["create_errors"] += 154 stats["create_count"] += 155 try_send("create")56
57def update(key, value):58
59 print(f"Updating...")60
61 db[key] = value62 stats["update_response_times"].append(random.uniform(0.5, 1.0))63 if random.choice([True, False]):64 stats["update_errors"] += 165 stats["update_count"] += 166 try_send("update")67
68def delete(key):69
70 print(f"Deleting...")71
72 db.pop(key, None)73 stats["delete_response_times"].append(random.uniform(0.5, 1.0))74 if random.choice([True, False]):75 stats["delete_errors"] += 176 stats["delete_count"] += 177 try_send("delete")78
79def try_send(type_):80
81 print("try_send")82
83def send_metrics(type_, interval_ms):84 85 print("sending metrics...")86
87 keys = GaugeMetric("fdb_keys", len(db))88 db_size = GaugeMetric("fdb_size", getsizeof(db))89
90 errors = CountMetric(91 name=f"fdb_{type_}_errors",92 value=stats[f"{type_}_errors"],93 interval_ms=interval_ms94 )95
96 cache_hits = CountMetric(97 name=f"fdb_cache_hits",98 value=stats["cache_hit"],99 interval_ms=interval_ms100 )101
102 response_times = stats[f"{type_}_response_times"]103 response_time_summary = SummaryMetric(104 f"fdb_{type_}_responses",105 count=len(response_times),106 min=min(response_times),107 max=max(response_times),108 sum=sum(response_times),109 interval_ms=interval_ms,110 )111
112 batch = [keys, db_size, errors, cache_hits, response_time_summary]113 response = metric_client.send_batch(batch)114 response.raise_for_status()115 print("Sent metrics successfully!")116 clear(type_)117
118def clear(type_):119 stats[f"{type_}_response_times"] = []120 stats[f"{type_}_errors"] = 0121 stats["cache_hit"] = 0122 stats[f"{type_}_count"] = 0123 last_push[type_] = datetime.datetime.now()
Here, you configure your platform to use GaugeMetric
, CountMetric
, and SummaryMetric
to report metrics to New Relic.
Amend the try_send
module to send these metrics every 2 second.
1import os2import random3import datetime4from sys import getsizeof5
6from newrelic_telemetry_sdk import MetricClient, GaugeMetric, CountMetric, SummaryMetric7
8metric_client = MetricClient(os.environ["NEW_RELIC_LICENSE_KEY"])9
10db = {}11stats = {12 "read_response_times": [],13 "read_errors": 0,14 "read_count": 0,15 "create_response_times": [],16 "create_errors": 0,17 "create_count": 0,18 "update_response_times": [],19 "update_errors": 0,20 "update_count": 0,21 "delete_response_times": [],22 "delete_errors": 0,23 "delete_count": 0,24 "cache_hit": 0,25}26last_push = {27 "read": datetime.datetime.now(),28 "create": datetime.datetime.now(),29 "update": datetime.datetime.now(),30 "delete": datetime.datetime.now(),31}32
33def read(key):34
35 print(f"Reading...")36
37 if random.randint(0, 30) > 10:38 stats["cache_hit"] += 139
40 stats["read_response_times"].append(random.uniform(0.5, 1.0))41 if random.choice([True, False]):42 stats["read_errors"] += 143 stats["read_count"] += 144 try_send("read")45
46def create(key, value):47
48 print(f"Writing...")49
50 db[key] = value51 stats["create_response_times"].append(random.uniform(0.5, 1.0))52 if random.choice([True, False]):53 stats["create_errors"] += 154 stats["create_count"] += 155 try_send("create")56
57def update(key, value):58
59 print(f"Updating...")60
61 db[key] = value62 stats["update_response_times"].append(random.uniform(0.5, 1.0))63 if random.choice([True, False]):64 stats["update_errors"] += 165 stats["update_count"] += 166 try_send("update")67
68def delete(key):69
70 print(f"Deleting...")71
72 db.pop(key, None)73 stats["delete_response_times"].append(random.uniform(0.5, 1.0))74 if random.choice([True, False]):75 stats["delete_errors"] += 176 stats["delete_count"] += 177 try_send("delete")78
79def try_send(type_):80
81 print("try_send")82
83 now = datetime.datetime.now()84 interval_ms = (now - last_push[type_]).total_seconds() * 100085 if interval_ms >= 2000:86 send_metrics(type_, interval_ms)87
88def send_metrics(type_, interval_ms):89 90 print("sending metrics...")91
92 keys = GaugeMetric("fdb_keys", len(db))93 db_size = GaugeMetric("fdb_size", getsizeof(db))94
95 errors = CountMetric(96 name=f"fdb_{type_}_errors",97 value=stats[f"{type_}_errors"],98 interval_ms=interval_ms99 )100
101 cache_hits = CountMetric(102 name=f"fdb_cache_hits",103 value=stats["cache_hit"],104 interval_ms=interval_ms105 )106
107 response_times = stats[f"{type_}_response_times"]108 response_time_summary = SummaryMetric(109 f"fdb_{type_}_responses",110 count=len(response_times),111 min=min(response_times),112 max=max(response_times),113 sum=sum(response_times),114 interval_ms=interval_ms,115 )116
117 batch = [keys, db_size, errors, cache_hits, response_time_summary]118 response = metric_client.send_batch(batch)119 response.raise_for_status()120 print("Sent metrics successfully!")121 clear(type_)122
123def clear(type_):124 stats[f"{type_}_response_times"] = []125 stats[f"{type_}_errors"] = 0126 stats["cache_hit"] = 0127 stats[f"{type_}_count"] = 0128 last_push[type_] = datetime.datetime.now()
Your platform will now report all the configured metrics every 2 seconds.
Navigate to the root of your application at build-a-quickstart-lab/send-metrics/flashDB.
Run your services to verify that it is reporting metrics.
$python simulator.pyWriting...try_sendWriting...try_sendReading...try_sendReading...try_sendWriting...try_sendWriting...try_sendReading...sending metrics...Sent metrics successfully!
Alternative Options
If the language SDK doesn’t fit your needs or you’d like something more customized to send metrics to New Relic, try out one of our other options:
- Manual Implementation: If our SDK in your preferred language doesn’t support metrics, you can always manually instrument your own library to make a POST request to the New Relic Metric API.
- Prometheus Data: Prometheus data can be sent to New Relic in two ways, remote write and OpenMetrics. At a very high level, you should use remote write if you manage your own Prometheus servers and OpenMetrics if you don't.
In this procedure, you instrumented your service to send metrics to New Relic. Next, instrument it to send events.
Course
This procedure is a part of course that teaches you how to build a quickstart. Continue to next lesson, send events from your product.