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've completed the last procedure, send logs from your product before proceeding with this one.
Traces capture details of a single request as it moves through a system. They’re composed of spans, which are data structures that represent individual operations in the flow of execution.
New Relic, provides you a variety of ways to instrument your application to send traces to our Trace API.
In this lesson, you learn to send traces 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 such as Python, Java, Node/TypeScript. These send data to our data ingest APIs, including our Trace API.
In this lesson, you learn how to install and use the Python telemetry SDK to report your first span to New Relic.
Report your first span
Change to the send-traces/flashDB direcrory of the course repository.
$cd ../../send-traces/flashDB
If you haven't already, install the newrelic-telemetry-sdk
package.
$pip install newrelic-telemetry-sdk
Open db.py file in the IDE of your choice and configure the SpanClient
.
1import os2import random3import datetime4from sys import getsizeof5import psutil6
7from newrelic_telemetry_sdk import MetricClient, GaugeMetric, CountMetric, SummaryMetric8from newrelic_telemetry_sdk import EventClient, Event9from newrelic_telemetry_sdk import LogClient, Log10from newrelic_telemetry_sdk import SpanClient11
12metric_client = MetricClient(os.environ["NEW_RELIC_LICENSE_KEY"])13event_client = EventClient(os.environ["NEW_RELIC_LICENSE_KEY"])14log_client = LogClient(os.environ["NEW_RELIC_LICENSE_KEY"])15span_client = SpanClient(os.environ["NEW_RELIC_LICENSE_KEY"])16
17db = {}18stats = {19 "read_response_times": [],20 "read_errors": 0,21 "read_count": 0,22 "create_response_times": [],23 "create_errors": 0,24 "create_count": 0,25 "update_response_times": [],26 "update_errors": 0,27 "update_count": 0,28 "delete_response_times": [],29 "delete_errors": 0,30 "delete_count": 0,31 "cache_hit": 0,32}33last_push = {34 "read": datetime.datetime.now(),35 "create": datetime.datetime.now(),36 "update": datetime.datetime.now(),37 "delete": datetime.datetime.now(),38}39
40def read(key):41
42 print(f"Reading...")43
44 if random.randint(0, 30) > 10:45 stats["cache_hit"] += 146
47 stats["read_response_times"].append(random.uniform(0.5, 1.0))48 if random.choice([True, False]):49 stats["read_errors"] += 150 stats["read_count"] += 151 try_send("read")52
53def create(key, value):54
55 print(f"Writing...")56
57 db[key] = value58 stats["create_response_times"].append(random.uniform(0.5, 1.0))59 if random.choice([True, False]):60 stats["create_errors"] += 161 stats["create_count"] += 162 try_send("create")63
64def update(key, value):65
66 print(f"Updating...")67
68 db[key] = value69 stats["update_response_times"].append(random.uniform(0.5, 1.0))70 if random.choice([True, False]):71 stats["update_errors"] += 172 stats["update_count"] += 173 try_send("update")74
75def delete(key):76
77 print(f"Deleting...")78
79 db.pop(key, None)80 stats["delete_response_times"].append(random.uniform(0.5, 1.0))81 if random.choice([True, False]):82 stats["delete_errors"] += 183 stats["delete_count"] += 184 try_send("delete")85
86def try_send(type_):87
88 print("try_send")89
90 now = datetime.datetime.now()91 interval_ms = (now - last_push[type_]).total_seconds() * 100092 if interval_ms >= 2000:93 send_metrics(type_, interval_ms)94 send_event(type_)95 send_logs()96
97def send_metrics(type_, interval_ms):98 99 print("sending metrics...")100
101 keys = GaugeMetric("fdb_keys", len(db))102 db_size = GaugeMetric("fdb_size", getsizeof(db))103
104 errors = CountMetric(105 name=f"fdb_{type_}_errors",106 value=stats[f"{type_}_errors"],107 interval_ms=interval_ms108 )109
110 cache_hits = CountMetric(111 name=f"fdb_cache_hits",112 value=stats["cache_hit"],113 interval_ms=interval_ms114 )115
116 response_times = stats[f"{type_}_response_times"]117 response_time_summary = SummaryMetric(118 f"fdb_{type_}_responses",119 count=len(response_times),120 min=min(response_times),121 max=max(response_times),122 sum=sum(response_times),123 interval_ms=interval_ms,124 )125
126 batch = [keys, db_size, errors, cache_hits, response_time_summary]127 response = metric_client.send_batch(batch)128 response.raise_for_status()129 print("Sent metrics successfully!")130 clear(type_)131
132def send_event(type_):133
134 print("sending event...")135
136 count = Event(137 "fdb_method", {"method": type_}138 )139
140 response = event_client.send_batch(count)141 response.raise_for_status()142 print("Event sent successfully!")143
144def send_logs():145
146 print("sending log...")147
148 process = psutil.Process(os.getpid())149 memory_usage = process.memory_percent()150
151 log = Log("FlashDB is using " + str(round(memory_usage * 100, 2)) + "% memory")152
153 response = log_client.send(log)154 response.raise_for_status()155 print("Log sent successfully!")156
157def clear(type_):158 stats[f"{type_}_response_times"] = []159 stats[f"{type_}_errors"] = 0160 stats["cache_hit"] = 0161 stats[f"{type_}_count"] = 0162 last_push[type_] = datetime.datetime.now()
Important
This example expects an environment variable called $NEW_RELIC_LICENSE_KEY
.
Instrument your app to report a span to New Relic.
1import os2import random3import datetime4from sys import getsizeof5import psutil6import time7
8from newrelic_telemetry_sdk import MetricClient, GaugeMetric, CountMetric, SummaryMetric9from newrelic_telemetry_sdk import EventClient, Event10from newrelic_telemetry_sdk import LogClient, Log11from newrelic_telemetry_sdk import SpanClient, Span12
13metric_client = MetricClient(os.environ["NEW_RELIC_LICENSE_KEY"])14event_client = EventClient(os.environ["NEW_RELIC_LICENSE_KEY"])15log_client = LogClient(os.environ["NEW_RELIC_LICENSE_KEY"])16span_client = SpanClient(os.environ["NEW_RELIC_LICENSE_KEY"])17
18db = {}19stats = {20 "read_response_times": [],21 "read_errors": 0,22 "read_count": 0,23 "create_response_times": [],24 "create_errors": 0,25 "create_count": 0,26 "update_response_times": [],27 "update_errors": 0,28 "update_count": 0,29 "delete_response_times": [],30 "delete_errors": 0,31 "delete_count": 0,32 "cache_hit": 0,33}34last_push = {35 "read": datetime.datetime.now(),36 "create": datetime.datetime.now(),37 "update": datetime.datetime.now(),38 "delete": datetime.datetime.now(),39}40
41def read(key):42
43 print(f"Reading...")44
45 if random.randint(0, 30) > 10:46 stats["cache_hit"] += 147
48 stats["read_response_times"].append(random.uniform(0.5, 1.0))49 if random.choice([True, False]):50 stats["read_errors"] += 151 stats["read_count"] += 152 try_send("read")53
54def create(key, value):55
56 print(f"Writing...")57
58 db[key] = value59 stats["create_response_times"].append(random.uniform(0.5, 1.0))60 if random.choice([True, False]):61 stats["create_errors"] += 162 stats["create_count"] += 163 try_send("create")64
65def update(key, value):66
67 print(f"Updating...")68
69 db[key] = value70 stats["update_response_times"].append(random.uniform(0.5, 1.0))71 if random.choice([True, False]):72 stats["update_errors"] += 173 stats["update_count"] += 174 try_send("update")75
76def delete(key):77
78 print(f"Deleting...")79
80 db.pop(key, None)81 stats["delete_response_times"].append(random.uniform(0.5, 1.0))82 if random.choice([True, False]):83 stats["delete_errors"] += 184 stats["delete_count"] += 185 try_send("delete")86
87def try_send(type_):88
89 print("try_send")90
91 now = datetime.datetime.now()92 interval_ms = (now - last_push[type_]).total_seconds() * 100093 if interval_ms >= 2000:94 send_metrics(type_, interval_ms)95 send_event(type_)96 send_logs()97
98def send_metrics(type_, interval_ms):99 100 print("sending metrics...")101
102 keys = GaugeMetric("fdb_keys", len(db))103 db_size = GaugeMetric("fdb_size", getsizeof(db))104
105 errors = CountMetric(106 name=f"fdb_{type_}_errors",107 value=stats[f"{type_}_errors"],108 interval_ms=interval_ms109 )110
111 cache_hits = CountMetric(112 name=f"fdb_cache_hits",113 value=stats["cache_hit"],114 interval_ms=interval_ms115 )116
117 response_times = stats[f"{type_}_response_times"]118 response_time_summary = SummaryMetric(119 f"fdb_{type_}_responses",120 count=len(response_times),121 min=min(response_times),122 max=max(response_times),123 sum=sum(response_times),124 interval_ms=interval_ms,125 )126
127 batch = [keys, db_size, errors, cache_hits, response_time_summary]128 response = metric_client.send_batch(batch)129 response.raise_for_status()130 print("Sent metrics successfully!")131 clear(type_)132
133def send_event(type_):134
135 print("sending event...")136
137 count = Event(138 "fdb_method", {"method": type_}139 )140
141 response = event_client.send_batch(count)142 response.raise_for_status()143 print("Event sent successfully!")144
145def send_logs():146
147 print("sending log...")148
149 process = psutil.Process(os.getpid())150 memory_usage = process.memory_percent()151
152 log = Log("FlashDB is using " + str(round(memory_usage * 100, 2)) + "% memory")153
154 response = log_client.send(log)155 response.raise_for_status()156 print("Log sent successfully!")157
158def send_spans():159
160 print("sending span...")161
162 with Span(name="sleep") as span:163 time.sleep(0.5)164
165 response = span_client.send(span)166 response.raise_for_status()167 print("Span sleep sent successfully!")168
169def clear(type_):170 stats[f"{type_}_response_times"] = []171 stats[f"{type_}_errors"] = 0172 stats["cache_hit"] = 0173 stats[f"{type_}_count"] = 0174 last_push[type_] = datetime.datetime.now()
Here, you instrument your platform to send a simple sleep span to New Relic.
Amend the try_send
module to send the span every 2 second.
1import os2import random3import datetime4from sys import getsizeof5import psutil6import time7
8from newrelic_telemetry_sdk import MetricClient, GaugeMetric, CountMetric, SummaryMetric9from newrelic_telemetry_sdk import EventClient, Event10from newrelic_telemetry_sdk import LogClient, Log11from newrelic_telemetry_sdk import SpanClient, Span12
13metric_client = MetricClient(os.environ["NEW_RELIC_LICENSE_KEY"])14event_client = EventClient(os.environ["NEW_RELIC_LICENSE_KEY"])15log_client = LogClient(os.environ["NEW_RELIC_LICENSE_KEY"])16span_client = SpanClient(os.environ["NEW_RELIC_LICENSE_KEY"])17
18db = {}19stats = {20 "read_response_times": [],21 "read_errors": 0,22 "read_count": 0,23 "create_response_times": [],24 "create_errors": 0,25 "create_count": 0,26 "update_response_times": [],27 "update_errors": 0,28 "update_count": 0,29 "delete_response_times": [],30 "delete_errors": 0,31 "delete_count": 0,32 "cache_hit": 0,33}34last_push = {35 "read": datetime.datetime.now(),36 "create": datetime.datetime.now(),37 "update": datetime.datetime.now(),38 "delete": datetime.datetime.now(),39}40
41def read(key):42
43 print(f"Reading...")44
45 if random.randint(0, 30) > 10:46 stats["cache_hit"] += 147
48 stats["read_response_times"].append(random.uniform(0.5, 1.0))49 if random.choice([True, False]):50 stats["read_errors"] += 151 stats["read_count"] += 152 try_send("read")53
54def create(key, value):55
56 print(f"Writing...")57
58 db[key] = value59 stats["create_response_times"].append(random.uniform(0.5, 1.0))60 if random.choice([True, False]):61 stats["create_errors"] += 162 stats["create_count"] += 163 try_send("create")64
65def update(key, value):66
67 print(f"Updating...")68
69 db[key] = value70 stats["update_response_times"].append(random.uniform(0.5, 1.0))71 if random.choice([True, False]):72 stats["update_errors"] += 173 stats["update_count"] += 174 try_send("update")75
76def delete(key):77
78 print(f"Deleting...")79
80 db.pop(key, None)81 stats["delete_response_times"].append(random.uniform(0.5, 1.0))82 if random.choice([True, False]):83 stats["delete_errors"] += 184 stats["delete_count"] += 185 try_send("delete")86
87def try_send(type_):88
89 print("try_send")90
91 now = datetime.datetime.now()92 interval_ms = (now - last_push[type_]).total_seconds() * 100093 if interval_ms >= 2000:94 send_metrics(type_, interval_ms)95 send_event(type_)96 send_logs()97 send_spans()98
99def send_metrics(type_, interval_ms):100 101 print("sending metrics...")102
103 keys = GaugeMetric("fdb_keys", len(db))104 db_size = GaugeMetric("fdb_size", getsizeof(db))105
106 errors = CountMetric(107 name=f"fdb_{type_}_errors",108 value=stats[f"{type_}_errors"],109 interval_ms=interval_ms110 )111
112 cache_hits = CountMetric(113 name=f"fdb_cache_hits",114 value=stats["cache_hit"],115 interval_ms=interval_ms116 )117
118 response_times = stats[f"{type_}_response_times"]119 response_time_summary = SummaryMetric(120 f"fdb_{type_}_responses",121 count=len(response_times),122 min=min(response_times),123 max=max(response_times),124 sum=sum(response_times),125 interval_ms=interval_ms,126 )127
128 batch = [keys, db_size, errors, cache_hits, response_time_summary]129 response = metric_client.send_batch(batch)130 response.raise_for_status()131 print("Sent metrics successfully!")132 clear(type_)133
134def send_event(type_):135
136 print("sending event...")137
138 count = Event(139 "fdb_method", {"method": type_}140 )141
142 response = event_client.send_batch(count)143 response.raise_for_status()144 print("Event sent successfully!")145
146def send_logs():147
148 print("sending log...")149
150 process = psutil.Process(os.getpid())151 memory_usage = process.memory_percent()152
153 log = Log("FlashDB is using " + str(round(memory_usage * 100, 2)) + "% memory")154
155 response = log_client.send(log)156 response.raise_for_status()157 print("Log sent successfully!")158
159def send_spans():160
161 print("sending span...")162
163 with Span(name="sleep") as span:164 time.sleep(0.5)165
166 response = span_client.send(span)167 response.raise_for_status()168 print("Span sleep sent successfully!")169
170def clear(type_):171 stats[f"{type_}_response_times"] = []172 stats[f"{type_}_errors"] = 0173 stats["cache_hit"] = 0174 stats[f"{type_}_count"] = 0175 last_push[type_] = datetime.datetime.now()
Your platform will now report this span every 2 seconds.
Navigate to the root of your application at build-a-quickstart-lab/send-traces/flashDB.
Run your services to verify that it is reporting the span.
$python simulator.pyWriting...try_sendReading...try_sendReading...try_sendWriting...try_sendWriting...try_sendReading...sending metrics...Sent metrics successfully!sending event...Event sent successfully!sending log...Log sent successfully!sending span...Span sleep sent successfully!
Alternative Options
If the language SDK doesn’t fit your needs, try out one of our other options:
- Existing Zipkin instrumentation: if you have an existing Zipkin implementation, you can simply change the endpoint to New Relic to report your data. Read our documentation to report data from existing Zipkin instrumentation.
- Manual Implementation: If the previous options don’t fit your requirements, you can always manually instrument your own library to make a POST request to the New Relic Trace API.
Your platform is now reporting data to New Relic. Next, you observe this data in New Relic using dashboard.
Course
This procedure is a part of course that teaches you how to build a quickstart. Continue to next lesson, create a dashboard.