Skip to content
This repository was archived by the owner on Jul 21, 2021. It is now read-only.

Commit 8422866

Browse files
Merge pull request lightstep#53 from lightstep/sarah/LS-5226
LS-5226: Add support for Proto over HTTP
2 parents ffc71ff + 9d9de29 commit 8422866

File tree

13 files changed

+493
-222
lines changed

13 files changed

+493
-222
lines changed

examples/http/context_in_headers.py

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,17 @@
2626
)
2727
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
2828

29-
3029
import opentracing
3130
import opentracing.ext.tags
3231
import lightstep
3332

33+
3434
class RemoteHandler(BaseHTTPRequestHandler):
3535
"""This handler receives the request from the client.
3636
"""
37+
3738
def do_GET(self):
3839
with before_answering_request(self, opentracing.tracer) as server_span:
39-
4040
server_span.log_event('request received', self.path)
4141

4242
self.send_response(200)
@@ -81,8 +81,8 @@ def before_answering_request(handler, tracer):
8181
span = None
8282
if extracted_context:
8383
span = tracer.start_span(
84-
operation_name=operation,
85-
child_of=extracted_context)
84+
operation_name=operation,
85+
child_of=extracted_context)
8686
else:
8787
print('ERROR: Context missing, starting new trace')
8888
global _exit_code
@@ -116,24 +116,29 @@ def lightstep_tracer_from_args():
116116
"""
117117
parser = argparse.ArgumentParser()
118118
parser.add_argument('--token', help='Your LightStep access token.',
119-
default='{your_access_token}')
119+
default='{your_access_token}')
120120
parser.add_argument('--host', help='The LightStep reporting service host to contact.',
121-
default='collector.lightstep.com')
121+
default='collector.lightstep.com')
122122
parser.add_argument('--port', help='The LightStep reporting service port.',
123-
type=int, default=443)
124-
parser.add_argument('--use_tls', help='Whether to use TLS for reporting',
125-
type=bool, default=True)
123+
type=int, default=443)
124+
parser.add_argument('--no_tls', help='Disable TLS for reporting',
125+
dest="no_tls", action='store_true')
126126
parser.add_argument('--component_name', help='The LightStep component name',
127-
default='TrivialExample')
127+
default='TrivialExample')
128128
args = parser.parse_args()
129129

130+
if args.no_tls:
131+
collector_encryption = 'none'
132+
else:
133+
collector_encryption = 'tls'
134+
130135
return lightstep.Tracer(
131-
component_name=args.component_name,
132-
access_token=args.token,
133-
collector_host=args.host,
134-
collector_port=args.port,
135-
collector_encryption=('tls' if args.use_tls else 'none'),
136-
)
136+
component_name=args.component_name,
137+
access_token=args.token,
138+
collector_host=args.host,
139+
collector_port=args.port,
140+
collector_encryption=collector_encryption,
141+
)
137142

138143

139144
if __name__ == '__main__':

examples/nontrivial/main.py

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
library.
44
"""
55
import argparse
6-
import contextlib
76
import sys
87
import time
98
import threading
@@ -16,13 +15,15 @@
1615
import opentracing
1716
import lightstep
1817

18+
1919
def sleep_dot():
2020
"""Short sleep and writes a dot to the STDOUT.
2121
"""
2222
time.sleep(0.05)
2323
sys.stdout.write('.')
2424
sys.stdout.flush()
2525

26+
2627
def add_spans():
2728
"""Calls the opentracing API, doesn't use any LightStep-specific code.
2829
"""
@@ -69,18 +70,23 @@ def lightstep_tracer_from_args():
6970
default='collector.lightstep.com')
7071
parser.add_argument('--port', help='The LightStep reporting service port.',
7172
type=int, default=443)
72-
parser.add_argument('--use_tls', help='Whether to use TLS for reporting',
73-
type=bool, default=True)
73+
parser.add_argument('--no_tls', help='Disable TLS for reporting',
74+
dest="no_tls", action='store_true')
7475
parser.add_argument('--component_name', help='The LightStep component name',
7576
default='NonTrivialExample')
7677
args = parser.parse_args()
7778

79+
if args.no_tls:
80+
collector_encryption = 'none'
81+
else:
82+
collector_encryption = 'tls'
83+
7884
return lightstep.Tracer(
79-
component_name=args.component_name,
80-
access_token=args.token,
81-
collector_host=args.host,
82-
collector_port=args.port,
83-
collector_encryption=('tls' if args.use_tls else 'none'))
85+
component_name=args.component_name,
86+
access_token=args.token,
87+
collector_host=args.host,
88+
collector_port=args.port,
89+
collector_encryption=collector_encryption)
8490

8591

8692
if __name__ == '__main__':

examples/trivial/main.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
11
"""Simple example showing several generations of spans in a trace.
22
"""
33
import argparse
4-
import contextlib
54
import sys
65
import time
76
import traceback
87

98
import opentracing
109
import lightstep.tracer
1110

11+
1212
def sleep_dot():
1313
"""Short sleep and writes a dot to the STDOUT.
1414
"""
1515
time.sleep(0.05)
1616
sys.stdout.write('.')
1717
sys.stdout.flush()
1818

19+
1920
def add_spans():
2021
"""Calls the opentracing API, doesn't use any LightStep-specific code.
2122
"""
@@ -62,19 +63,28 @@ def lightstep_tracer_from_args():
6263
default='collector.lightstep.com')
6364
parser.add_argument('--port', help='The LightStep reporting service port.',
6465
type=int, default=443)
65-
parser.add_argument('--use_tls', help='Whether to use TLS for reporting',
66-
type=bool, default=True)
66+
parser.add_argument('--no_tls', help='Disable TLS for reporting',
67+
dest="no_tls", action='store_true')
6768
parser.add_argument('--component_name', help='The LightStep component name',
6869
default='TrivialExample')
70+
parser.add_argument('--use_thrift', help='Use Thrift over http',
71+
dest="use_thrift", action='store_true')
6972
args = parser.parse_args()
7073

74+
if args.no_tls:
75+
collector_encryption = 'none'
76+
else:
77+
collector_encryption = 'tls'
78+
7179
return lightstep.Tracer(
7280
component_name=args.component_name,
7381
access_token=args.token,
7482
collector_host=args.host,
7583
collector_port=args.port,
7684
verbosity=1,
77-
collector_encryption=('tls' if args.use_tls else 'none'))
85+
collector_encryption=collector_encryption,
86+
use_thrift=args.use_thrift,
87+
use_http=not args.use_thrift)
7888

7989

8090
if __name__ == '__main__':

lightstep/converter.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
from abc import ABCMeta, abstractmethod
2+
3+
4+
class Converter(object):
5+
"""Converter is a simple abstract interface for converting span data to wire compatible formats for the Satellites.
6+
"""
7+
8+
__metaclass__ = ABCMeta
9+
10+
@abstractmethod
11+
def create_auth(self, access_token):
12+
pass
13+
14+
@abstractmethod
15+
def create_runtime(self, component_name, tags, guid):
16+
pass
17+
18+
@abstractmethod
19+
def create_span_record(self, span, guid):
20+
pass
21+
22+
@abstractmethod
23+
def append_attribute(self, span_record, key, value):
24+
pass
25+
26+
@abstractmethod
27+
def append_join_id(self, span_record, key, value):
28+
pass
29+
30+
@abstractmethod
31+
def append_log(self, span_record, log):
32+
pass
33+
34+
@abstractmethod
35+
def create_report(self, runtime, span_records):
36+
pass
37+
38+
@abstractmethod
39+
def combine_span_records(self, report_request, span_records):
40+
pass
41+
42+
@abstractmethod
43+
def num_span_records(self, report_request):
44+
pass
45+
46+
@abstractmethod
47+
def get_span_records(self, report_request):
48+
pass
49+
50+
@abstractmethod
51+
def get_span_name(self, span_record):
52+
pass

lightstep/http_connection.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
""" Connection class establishes HTTP connection with server.
2+
Utilized to send Proto Report Requests.
3+
"""
4+
import threading
5+
import requests
6+
7+
from lightstep.collector_pb2 import ReportResponse
8+
9+
10+
class _HTTPConnection(object):
11+
"""Instances of _Connection are used to establish a connection to the
12+
server via HTTP protocol.
13+
"""
14+
def __init__(self, collector_url, timeout_seconds):
15+
self._collector_url = collector_url
16+
self._lock = threading.Lock()
17+
self.ready = True
18+
self._timeout_seconds = timeout_seconds
19+
20+
def open(self):
21+
"""Establish HTTP connection to the server.
22+
"""
23+
pass
24+
25+
# May throw an Exception on failure.
26+
def report(self, *args, **kwargs):
27+
"""Report to the server."""
28+
auth = args[0]
29+
report = args[1]
30+
with self._lock:
31+
try:
32+
report.auth.access_token = auth.access_token
33+
headers = {"Content-Type": "application/octet-stream",
34+
"Accept": "application/octet-stream"}
35+
36+
r = requests.post(
37+
self._collector_url,
38+
headers=headers,
39+
data=report.SerializeToString(),
40+
timeout=self._timeout_seconds)
41+
resp = ReportResponse()
42+
resp.ParseFromString(r.content)
43+
return resp
44+
except requests.exceptions.RequestException as err:
45+
raise err
46+
47+
def close(self):
48+
"""Close HTTP connection to the server."""
49+
self.ready = False
50+
pass

lightstep/http_converter.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
from lightstep.collector_pb2 import Auth, ReportRequest, Span, Reporter, KeyValue, Reference, SpanContext
2+
from lightstep.converter import Converter
3+
from . import util
4+
from . import version as tracer_version
5+
import sys
6+
from google.protobuf.timestamp_pb2 import Timestamp
7+
8+
9+
class HttpConverter(Converter):
10+
11+
def create_auth(self, access_token):
12+
auth = Auth()
13+
auth.access_token = access_token
14+
return auth
15+
16+
def create_runtime(self, component_name, tags, guid):
17+
if component_name is None:
18+
component_name = sys.argv[0]
19+
20+
python_version = '.'.join(map(str, sys.version_info[0:3]))
21+
22+
if tags is None:
23+
tags = {}
24+
tracer_tags = tags.copy()
25+
26+
tracer_tags.update({
27+
'lightstep.tracer_platform': 'python',
28+
'lightstep.tracer_platform_version': python_version,
29+
'lightstep.tracer_version': tracer_version.LIGHTSTEP_PYTHON_TRACER_VERSION,
30+
'lightstep.component_name': component_name,
31+
'lightstep.guid': util._id_to_hex(guid),
32+
})
33+
34+
# Convert tracer_tags to a list of KeyValue pairs.
35+
runtime_attrs = [KeyValue(key=k, string_value=util._coerce_str(v)) for (k, v) in tracer_tags.items()]
36+
37+
return Reporter(reporter_id=guid, tags=runtime_attrs)
38+
39+
def create_span_record(self, span, guid):
40+
span_context = SpanContext(trace_id=span.context.trace_id,
41+
span_id=span.context.span_id)
42+
span_record = Span(span_context=span_context,
43+
operation_name=util._coerce_str(span.operation_name),
44+
start_timestamp=Timestamp(seconds=int(span.start_time)),
45+
duration_micros=int(util._time_to_micros(span.duration)))
46+
if span.parent_id is not None:
47+
reference = span_record.references.add()
48+
reference.relationship=Reference.CHILD_OF
49+
reference.span_context.span_id=span.parent_id
50+
51+
return span_record
52+
53+
def append_attribute(self, span_record, key, value):
54+
kv = span_record.tags.add()
55+
kv.key = key
56+
kv.string_value = value
57+
58+
def append_join_id(self, span_record, key, value):
59+
self.append_attribute(span_record, key, value)
60+
61+
def append_log(self, span_record, log):
62+
if log.key_values is not None and len(log.key_values) > 0:
63+
proto_log = span_record.logs.add()
64+
proto_log.timestamp.seconds=int(log.timestamp)
65+
for k, v in log.key_values.items():
66+
field = proto_log.fields.add()
67+
field.key = k
68+
field.string_value = util._coerce_str(v)
69+
70+
def create_report(self, runtime, span_records):
71+
return ReportRequest(reporter=runtime, spans=span_records)
72+
73+
def combine_span_records(self, report_request, span_records):
74+
report_request.spans.extend(span_records)
75+
return report_request.spans
76+
77+
def num_span_records(self, report_request):
78+
return len(report_request.spans)
79+
80+
def get_span_records(self, report_request):
81+
return report_request.spans
82+
83+
def get_span_name(self, span_record):
84+
return span_record.operation_name

0 commit comments

Comments
 (0)