diff options
Diffstat (limited to 'src/blkin')
29 files changed, 3116 insertions, 0 deletions
diff --git a/src/blkin/CMakeLists.txt b/src/blkin/CMakeLists.txt new file mode 100644 index 000000000..d9a25b1cb --- /dev/null +++ b/src/blkin/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 2.8.11) + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules/") +find_package(LTTng REQUIRED) + +# make && make test +enable_testing() + +add_subdirectory(blkin-lib) diff --git a/src/blkin/COPYRIGHT b/src/blkin/COPYRIGHT new file mode 100644 index 000000000..55828c9af --- /dev/null +++ b/src/blkin/COPYRIGHT @@ -0,0 +1,27 @@ +Copyright 2014 Marios Kogias <marioskogias@gmail.com> +All rights reserved. + +Redistribution and use in source and binary forms, with or +without modification, are permitted provided that the following +conditions are met: + + 1. Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + 2. Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESS +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/src/blkin/README.md b/src/blkin/README.md new file mode 100644 index 000000000..2c8a6c99e --- /dev/null +++ b/src/blkin/README.md @@ -0,0 +1,59 @@ +#blkin + +BlkKin is a project that enables you to trace low-overhead applications using +LTTng following the tracing semantics that are described in Google's [Dapper +Paper](http://static.googleusercontent.com/media/research.google.com/el//pubs/archive/36356.pdf) + +According to this paper the logged information is called `Annotation` and +belongs to a specific span and trace. Each trace is comprised of multiple spans +which are related with each other with causal relationships. So, the BlkKin +library gives the user the API to easily instrument C/C++ applications. In +order to instrument applications you should take a look at ``blkin-lib/tests`` +for some testcases and at the ``blkin-lib/zipkin_c.h`` file + +As a tracing backend BlkKin uses LTTng. So you must have LTTng installed. + +In order to build and install the lib, go to blkin-lib folder and: + +``` +make +make install +``` + +You should take a look at the examples to find out how to link the blkin lib +with your instrumented application. + +In order to visualize the aggregated information you can use Twitter's +[Zipkin](http://twitter.github.io/zipkin/) and send the data that you created, +by running the equivalent babeltrace plugin. In order to do you can run + +``` +./zipkin/src/babeltrace_zipkin.py </path/to/lttng/traces> -s <server_ip> +-p <port_number> + +``` + +within the babeltrace-plugins directory. + +In case you have not used the blkin-lib to instrument your application, you can +still send your data to a Scribe server. To do that you can use another +Babeltrace plugin. This plugin tranforms LTTng trace data to a JSON format and +sends them to a Scribe sever.To do so we can equivalently run + +``` +./json/src/babeltrace_json.py </path/to/lttng/traces> -s <server_ip> +-p <port_number> +``` +within the babeltrace-plugins directory + +Both of these plugins require that you have installed Babeltrace with its +Python bindings enabled. +The path to the lttng traces should not be the root directory but the directory +where the channel directories are included. + +## Dependencies + +* libboost-all-dev +* lttng-tools + +Note that BlkKin is tested only with LTTng2.4 diff --git a/src/blkin/babeltrace-plugins/.gitignore b/src/blkin/babeltrace-plugins/.gitignore new file mode 100644 index 000000000..c9b568f7e --- /dev/null +++ b/src/blkin/babeltrace-plugins/.gitignore @@ -0,0 +1,2 @@ +*.pyc +*.swp diff --git a/src/blkin/babeltrace-plugins/json/README.md b/src/blkin/babeltrace-plugins/json/README.md new file mode 100644 index 000000000..be0bbe2c4 --- /dev/null +++ b/src/blkin/babeltrace-plugins/json/README.md @@ -0,0 +1,5 @@ +babeltrace-json plugin +======================== + +This plugin enables us to send LTTng trace data to a Scribe server in a valid +json format diff --git a/src/blkin/babeltrace-plugins/json/src/babeltrace_json.py b/src/blkin/babeltrace-plugins/json/src/babeltrace_json.py new file mode 100755 index 000000000..0d21e0181 --- /dev/null +++ b/src/blkin/babeltrace-plugins/json/src/babeltrace_json.py @@ -0,0 +1,88 @@ +#!/usr/bin/python +# babeltrace_zipkin.py + +import sys +sys.path.append("../../babeltrace-plugins") +import json +import getopt +from babeltrace import * +from scribe_client import ScribeClient + +HELP = "Usage: python babeltrace_zipkin.py path/to/file -s <server> -p <port>" +CATEGORY = "LTTng" + + +def main(argv): + try: + path = argv[0] + except: + raise TypeError(HELP) + + try: + opts, args = getopt.getopt(argv[1:], "hs:p:") + except getopt.GetoptError: + raise TypeError(HELP) + + server = None + port = None + for opt, arg in opts: + if opt == '-h': + raise TypeError(HELP) + elif opt == '-s': + server = arg + elif opt == '-p': + port = arg + + if not server: + server = "localhost" + if not port: + port = 1463 + + # Open connection with scribe + scribe_client = ScribeClient(port, server) + + # Create TraceCollection and add trace: + traces = TraceCollection() + trace_handle = traces.add_trace(path, "ctf") + if trace_handle is None: + raise IOError("Error adding trace") + + #iterate over events + for event in traces.events: + data = dict() + + data["parent_span_id"]= event["parent_span_id"] + data['name'] = event["trace_name"] + data ["trace_id"] = event["trace_id"] + data["span_id"] = event["span_id"] + data['port'] = event['port_no'] + data['service_name'] = event['service_name'] + data['ip'] = event['ip'] + data['evemt'] = event['event'] + data['timestamp'] = event.timestamp + ''' + for k, v in event.items(): + field_type = event._field(k).type + data[k] = format_value(field_type, v) + ''' + json_data = json.dumps(data) + + #send data to scribe + scribe_client.log(CATEGORY, json_data) + + scribe_client.close() + + +def format_value(field_type, value): + + if field_type == 1: + return int(value) + elif field_type == 2: + return float(value) + elif field_type == 8: + return [x for x in value] + else: + return str(value) + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/src/blkin/babeltrace-plugins/scribe_client/__init__.py b/src/blkin/babeltrace-plugins/scribe_client/__init__.py new file mode 100644 index 000000000..503803846 --- /dev/null +++ b/src/blkin/babeltrace-plugins/scribe_client/__init__.py @@ -0,0 +1 @@ +from scribe_client import * diff --git a/src/blkin/babeltrace-plugins/scribe_client/scribe_client.py b/src/blkin/babeltrace-plugins/scribe_client/scribe_client.py new file mode 100644 index 000000000..b382ed995 --- /dev/null +++ b/src/blkin/babeltrace-plugins/scribe_client/scribe_client.py @@ -0,0 +1,31 @@ +#!/usr/bin/python +# scribe_client.py + +from scribe import scribe +from thrift.transport import TTransport, TSocket +from thrift.protocol import TBinaryProtocol + +class ScribeClient(object): + + def __init__(self, port, host): + print host + self.port = port + self.host = host + self.openConnection() + + def openConnection(self): + socket = TSocket.TSocket(host=self.host, port=self.port) + self.transport = TTransport.TFramedTransport(socket) + protocol = TBinaryProtocol.TBinaryProtocol(trans=self.transport, + strictRead=False, + strictWrite=False) + self.client = scribe.Client(protocol) + self.transport.open() + + def log(self, category, message): + log_entry = scribe.LogEntry(category, message) + result = self.client.Log(messages=[log_entry]) + return result # 0 for success + + def close(self): + self.transport.close() diff --git a/src/blkin/babeltrace-plugins/zipkin/README.md b/src/blkin/babeltrace-plugins/zipkin/README.md new file mode 100644 index 000000000..95cebe87b --- /dev/null +++ b/src/blkin/babeltrace-plugins/zipkin/README.md @@ -0,0 +1,6 @@ +babeltrace-zipkin plugin +======================== + +In order to use this plugin, the traces created by LTTng should follow a +specific format. This format is provided in zipkin_trace.h file. If this +format is not followed the traces will be dropped. diff --git a/src/blkin/babeltrace-plugins/zipkin/src/babeltrace_zipkin.py b/src/blkin/babeltrace-plugins/zipkin/src/babeltrace_zipkin.py new file mode 100755 index 000000000..5677338c9 --- /dev/null +++ b/src/blkin/babeltrace-plugins/zipkin/src/babeltrace_zipkin.py @@ -0,0 +1,69 @@ +#!/usr/bin/python +# babeltrace_zipkin.py + +import sys +sys.path.append("../../babeltrace-plugins") +import sys +import getopt +from babeltrace import * +from zipkin_logic.zipkin_client import ZipkinClient +HELP = "Usage: python babeltrace_zipkin.py path/to/file -s <server> -p <port>" + + +def main(argv): + try: + path = argv[0] + except: + raise TypeError(HELP) + + try: + opts, args = getopt.getopt(argv[1:], "hs:p:") + except getopt.GetoptError: + raise TypeError(HELP) + + server = None + port = None + for opt, arg in opts: + if opt == '-h': + raise TypeError(HELP) + elif opt == '-s': + server = arg + elif opt == '-p': + port = arg + + if not server: + server = "83.212.113.88" + if not port: + port = 1463 + + # Open connection with scribe + zipkin = ZipkinClient(port, server) + + # Create TraceCollection and add trace: + traces = TraceCollection() + trace_handle = traces.add_trace(path, "ctf") + if trace_handle is None: + raise IOError("Error adding trace") + + for event in traces.events: + name = event.name + try: + provider, kind = name.split(":") + if provider != "zipkin": + raise + except: + continue + + #create a zipkin trace from event info + trace = zipkin.create_trace(event) + + #create a zipkin annotation from event info + annotation = zipkin.create_annotation(event, kind) + + #record the trace + zipkin.record(trace, annotation) + + zipkin.close() + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/src/blkin/babeltrace-plugins/zipkin/src/zipkin_logic/__init__.py b/src/blkin/babeltrace-plugins/zipkin/src/zipkin_logic/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/blkin/babeltrace-plugins/zipkin/src/zipkin_logic/__init__.py diff --git a/src/blkin/babeltrace-plugins/zipkin/src/zipkin_logic/formatters.py b/src/blkin/babeltrace-plugins/zipkin/src/zipkin_logic/formatters.py new file mode 100644 index 000000000..70874c0b6 --- /dev/null +++ b/src/blkin/babeltrace-plugins/zipkin/src/zipkin_logic/formatters.py @@ -0,0 +1,131 @@ +# Copyright 2012 Rackspace Hosting, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import json +import struct +import socket + +from thrift.protocol import TBinaryProtocol +from thrift.transport import TTransport + +import ttypes + + +def hex_str(n): + return '%0.16x' % (n,) + + +def json_formatter(traces, *json_args, **json_kwargs): + json_traces = [] + + for (trace, annotations) in traces: + json_trace = { + 'trace_id': hex_str(trace.trace_id), + 'span_id': hex_str(trace.span_id), + 'name': trace.name, + 'annotations': [] + } + + if trace.parent_span_id: + json_trace['parent_span_id'] = hex_str(trace.parent_span_id) + + for annotation in annotations: + json_annotation = { + 'key': annotation.name, + 'value': annotation.value, + 'type': annotation.annotation_type + } + + if annotation.endpoint: + json_annotation['host'] = { + 'ipv4': annotation.endpoint.ipv4, + 'port': annotation.endpoint.port, + 'service_name': annotation.endpoint.service_name + } + + json_trace['annotations'].append(json_annotation) + + json_traces.append(json_trace) + + return json.dumps(json_traces, *json_args, **json_kwargs) + + +def ipv4_to_int(ipv4): + return struct.unpack('!i', socket.inet_aton(ipv4))[0] + + +def base64_thrift(thrift_obj): + trans = TTransport.TMemoryBuffer() + tbp = TBinaryProtocol.TBinaryProtocol(trans) + + thrift_obj.write(tbp) + res = trans.getvalue().encode('base64').strip() + res = res.replace("\n","") + #print res + #print len(res) + return res + #return trans.getvalue().encode('base64').strip() + + +def binary_annotation_formatter(annotation, host=None): + annotation_types = { + 'string': ttypes.AnnotationType.STRING, + 'bytes': ttypes.AnnotationType.BYTES, + } + + annotation_type = annotation_types[annotation.annotation_type] + + value = annotation.value + + if isinstance(value, unicode): + value = value.encode('utf-8') + + return ttypes.BinaryAnnotation( + annotation.name, + value, + annotation_type, + host) + + +def base64_thrift_formatter(trace, annotations): + thrift_annotations = [] + binary_annotations = [] + + for annotation in annotations: + host = None + if annotation.endpoint: + host = ttypes.Endpoint( + ipv4=ipv4_to_int(annotation.endpoint.ipv4), + port=annotation.endpoint.port, + service_name=annotation.endpoint.service_name) + + if annotation.annotation_type == 'timestamp': + thrift_annotations.append(ttypes.Annotation( + timestamp=annotation.value, + value=annotation.name, + host=host)) + else: + binary_annotations.append( + binary_annotation_formatter(annotation, host)) + + thrift_trace = ttypes.Span( + trace_id=trace.trace_id, + name=trace.name, + id=trace.span_id, + parent_id=trace.parent_span_id, + annotations=thrift_annotations, + binary_annotations=binary_annotations + ) + + return base64_thrift(thrift_trace) diff --git a/src/blkin/babeltrace-plugins/zipkin/src/zipkin_logic/trace.py b/src/blkin/babeltrace-plugins/zipkin/src/zipkin_logic/trace.py new file mode 100644 index 000000000..e0a3ed2c3 --- /dev/null +++ b/src/blkin/babeltrace-plugins/zipkin/src/zipkin_logic/trace.py @@ -0,0 +1,137 @@ +import math +import time +import random + + +class Trace(object): + """ + An L{ITrace} provider which delegates to zero or more L{ITracers} and + allows setting a default L{IEndpoint} to associate with L{IAnnotation}s + + @ivar _tracers: C{list} of one or more L{ITracer} providers. + @ivar _endpoint: An L{IEndpoint} provider. + """ + def __init__(self, name, trace_id=None, span_id=None, + parent_span_id=None, tracers=None): + """ + @param name: C{str} describing the current span. + @param trace_id: C{int} or C{None} + @param span_id: C{int} or C{None} + @param parent_span_id: C{int} or C{None} + + @param tracers: C{list} of L{ITracer} providers, primarily useful + for unit testing. + """ + self.name = name + # If no trace_id and span_id are given we want to generate new + # 64-bit integer ids. + self.trace_id = trace_id + self.span_id = span_id + + # If no parent_span_id is given then we assume there is no parent span + # and leave it as None. + self.parent_span_id = parent_span_id + + # If no tracers are given we get the global list of tracers. + self._tracers = tracers + + # By default no endpoint will be associated with annotations recorded + # to this trace. + self._endpoint = None + + def __ne__(self, other): + return not self == other + + def __repr__(self): + return ( + '{0.__class__.__name__}({0.name!r}, trace_id={0.trace_id!r}, ' + 'span_id={0.span_id!r}, parent_span_id={0.parent_span_id!r})' + ).format(self) + + def set_endpoint(self, endpoint): + """ + Set a default L{IEndpoint} provider for the current L{Trace}. + All annotations recorded after this endpoint is set will use it, + unless they provide their own endpoint. + """ + self._endpoint = endpoint + + +class Endpoint(object): + + def __init__(self, ipv4, port, service_name): + """ + @param ipv4: C{str} ipv4 address. + @param port: C{int} port number. + @param service_name: C{str} service name. + """ + self.ipv4 = ipv4 + self.port = port + self.service_name = service_name + + def __ne__(self, other): + return not self == other + + def __repr__(self): + return ('{0.__class__.__name__}({0.ipv4!r}, {0.port!r}, ' + '{0.service_name!r})').format(self) + + +class Annotation(object): + + def __init__(self, name, value, annotation_type, endpoint=None): + """ + @param name: C{str} name of this annotation. + + @param value: A value of the appropriate type based on + C{annotation_type}. + + @param annotation_type: C{str} the expected type of our C{value}. + + @param endpoint: An optional L{IEndpoint} provider to associate with + this annotation or C{None} + """ + self.name = name + self.value = value + self.annotation_type = annotation_type + self.endpoint = endpoint + + def __ne__(self, other): + return not self == other + + def __repr__(self): + return ( + '{0.__class__.__name__}({0.name!r}, {0.value!r}, ' + '{0.annotation_type!r}, {0.endpoint})' + ).format(self) + + @classmethod + def timestamp(cls, name, timestamp=None): + if timestamp is None: + timestamp = math.trunc(time.time() * 1000 * 1000) + + return cls(name, timestamp, 'timestamp') + + @classmethod + def client_send(cls, timestamp=None): + return cls.timestamp(constants.CLIENT_SEND, timestamp) + + @classmethod + def client_recv(cls, timestamp=None): + return cls.timestamp(constants.CLIENT_RECV, timestamp) + + @classmethod + def server_send(cls, timestamp=None): + return cls.timestamp(constants.SERVER_SEND, timestamp) + + @classmethod + def server_recv(cls, timestamp=None): + return cls.timestamp(constants.SERVER_RECV, timestamp) + + @classmethod + def string(cls, name, value): + return cls(name, value, 'string') + + @classmethod + def bytes(cls, name, value): + return cls(name, value, 'bytes') diff --git a/src/blkin/babeltrace-plugins/zipkin/src/zipkin_logic/ttypes.py b/src/blkin/babeltrace-plugins/zipkin/src/zipkin_logic/ttypes.py new file mode 100644 index 000000000..8605559b7 --- /dev/null +++ b/src/blkin/babeltrace-plugins/zipkin/src/zipkin_logic/ttypes.py @@ -0,0 +1,453 @@ +# +# Autogenerated by Thrift Compiler (0.8.0) +# +# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING +# +# options string: py:twisted +# + +from thrift.Thrift import TType, TMessageType, TException + +from thrift.transport import TTransport +from thrift.protocol import TBinaryProtocol, TProtocol +try: + from thrift.protocol import fastbinary +except: + fastbinary = None + + +class AnnotationType: + BOOL = 0 + BYTES = 1 + I16 = 2 + I32 = 3 + I64 = 4 + DOUBLE = 5 + STRING = 6 + + _VALUES_TO_NAMES = { + 0: "BOOL", + 1: "BYTES", + 2: "I16", + 3: "I32", + 4: "I64", + 5: "DOUBLE", + 6: "STRING", + } + + _NAMES_TO_VALUES = { + "BOOL": 0, + "BYTES": 1, + "I16": 2, + "I32": 3, + "I64": 4, + "DOUBLE": 5, + "STRING": 6, + } + + +class Endpoint: + """ + Attributes: + - ipv4 + - port + - service_name + """ + + thrift_spec = ( + None, # 0 + (1, TType.I32, 'ipv4', None, None, ), # 1 + (2, TType.I16, 'port', None, None, ), # 2 + (3, TType.STRING, 'service_name', None, None, ), # 3 + ) + + def __init__(self, ipv4=None, port=None, service_name=None,): + self.ipv4 = ipv4 + self.port = port + self.service_name = service_name + + def read(self, iprot): + if iprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and isinstance(iprot.trans, TTransport.CReadableTransport) and self.thrift_spec is not None and fastbinary is not None: + fastbinary.decode_binary(self, iprot.trans, (self.__class__, self.thrift_spec)) + return + iprot.readStructBegin() + while True: + (fname, ftype, fid) = iprot.readFieldBegin() + if ftype == TType.STOP: + break + if fid == 1: + if ftype == TType.I32: + self.ipv4 = iprot.readI32(); + else: + iprot.skip(ftype) + elif fid == 2: + if ftype == TType.I16: + self.port = iprot.readI16(); + else: + iprot.skip(ftype) + elif fid == 3: + if ftype == TType.STRING: + self.service_name = iprot.readString(); + else: + iprot.skip(ftype) + else: + iprot.skip(ftype) + iprot.readFieldEnd() + iprot.readStructEnd() + + def write(self, oprot): + if oprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and self.thrift_spec is not None and fastbinary is not None: + oprot.trans.write(fastbinary.encode_binary(self, (self.__class__, self.thrift_spec))) + return + oprot.writeStructBegin('Endpoint') + if self.ipv4 is not None: + oprot.writeFieldBegin('ipv4', TType.I32, 1) + oprot.writeI32(self.ipv4) + oprot.writeFieldEnd() + if self.port is not None: + oprot.writeFieldBegin('port', TType.I16, 2) + oprot.writeI16(self.port) + oprot.writeFieldEnd() + if self.service_name is not None: + oprot.writeFieldBegin('service_name', TType.STRING, 3) + oprot.writeString(self.service_name) + oprot.writeFieldEnd() + oprot.writeFieldStop() + oprot.writeStructEnd() + + def validate(self): + return + + + def __repr__(self): + L = ['%s=%r' % (key, value) + for key, value in self.__dict__.iteritems()] + return '%s(%s)' % (self.__class__.__name__, ', '.join(L)) + + def __eq__(self, other): + return isinstance(other, self.__class__) and self.__dict__ == other.__dict__ + + def __ne__(self, other): + return not (self == other) + +class Annotation: + """ + Attributes: + - timestamp + - value + - host + """ + + thrift_spec = ( + None, # 0 + (1, TType.I64, 'timestamp', None, None, ), # 1 + (2, TType.STRING, 'value', None, None, ), # 2 + (3, TType.STRUCT, 'host', (Endpoint, Endpoint.thrift_spec), None, ), # 3 + ) + + def __init__(self, timestamp=None, value=None, host=None,): + self.timestamp = timestamp + self.value = value + self.host = host + + def read(self, iprot): + if iprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and isinstance(iprot.trans, TTransport.CReadableTransport) and self.thrift_spec is not None and fastbinary is not None: + fastbinary.decode_binary(self, iprot.trans, (self.__class__, self.thrift_spec)) + return + iprot.readStructBegin() + while True: + (fname, ftype, fid) = iprot.readFieldBegin() + if ftype == TType.STOP: + break + if fid == 1: + if ftype == TType.I64: + self.timestamp = iprot.readI64(); + else: + iprot.skip(ftype) + elif fid == 2: + if ftype == TType.STRING: + self.value = iprot.readString(); + else: + iprot.skip(ftype) + elif fid == 3: + if ftype == TType.STRUCT: + self.host = Endpoint() + self.host.read(iprot) + else: + iprot.skip(ftype) + else: + iprot.skip(ftype) + iprot.readFieldEnd() + iprot.readStructEnd() + + def write(self, oprot): + if oprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and self.thrift_spec is not None and fastbinary is not None: + oprot.trans.write(fastbinary.encode_binary(self, (self.__class__, self.thrift_spec))) + return + oprot.writeStructBegin('Annotation') + if self.timestamp is not None: + oprot.writeFieldBegin('timestamp', TType.I64, 1) + oprot.writeI64(self.timestamp) + oprot.writeFieldEnd() + if self.value is not None: + oprot.writeFieldBegin('value', TType.STRING, 2) + oprot.writeString(self.value) + oprot.writeFieldEnd() + if self.host is not None: + oprot.writeFieldBegin('host', TType.STRUCT, 3) + self.host.write(oprot) + oprot.writeFieldEnd() + oprot.writeFieldStop() + oprot.writeStructEnd() + + def validate(self): + return + + + def __repr__(self): + L = ['%s=%r' % (key, value) + for key, value in self.__dict__.iteritems()] + return '%s(%s)' % (self.__class__.__name__, ', '.join(L)) + + def __eq__(self, other): + return isinstance(other, self.__class__) and self.__dict__ == other.__dict__ + + def __ne__(self, other): + return not (self == other) + +class BinaryAnnotation: + """ + Attributes: + - key + - value + - annotation_type + - host + """ + + thrift_spec = ( + None, # 0 + (1, TType.STRING, 'key', None, None, ), # 1 + (2, TType.STRING, 'value', None, None, ), # 2 + (3, TType.I32, 'annotation_type', None, None, ), # 3 + (4, TType.STRUCT, 'host', (Endpoint, Endpoint.thrift_spec), None, ), # 4 + ) + + def __init__(self, key=None, value=None, annotation_type=None, host=None,): + self.key = key + self.value = value + self.annotation_type = annotation_type + self.host = host + + def read(self, iprot): + if iprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and isinstance(iprot.trans, TTransport.CReadableTransport) and self.thrift_spec is not None and fastbinary is not None: + fastbinary.decode_binary(self, iprot.trans, (self.__class__, self.thrift_spec)) + return + iprot.readStructBegin() + while True: + (fname, ftype, fid) = iprot.readFieldBegin() + if ftype == TType.STOP: + break + if fid == 1: + if ftype == TType.STRING: + self.key = iprot.readString(); + else: + iprot.skip(ftype) + elif fid == 2: + if ftype == TType.STRING: + self.value = iprot.readString(); + else: + iprot.skip(ftype) + elif fid == 3: + if ftype == TType.I32: + self.annotation_type = iprot.readI32(); + else: + iprot.skip(ftype) + elif fid == 4: + if ftype == TType.STRUCT: + self.host = Endpoint() + self.host.read(iprot) + else: + iprot.skip(ftype) + else: + iprot.skip(ftype) + iprot.readFieldEnd() + iprot.readStructEnd() + + def write(self, oprot): + if oprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and self.thrift_spec is not None and fastbinary is not None: + oprot.trans.write(fastbinary.encode_binary(self, (self.__class__, self.thrift_spec))) + return + oprot.writeStructBegin('BinaryAnnotation') + if self.key is not None: + oprot.writeFieldBegin('key', TType.STRING, 1) + oprot.writeString(self.key) + oprot.writeFieldEnd() + if self.value is not None: + oprot.writeFieldBegin('value', TType.STRING, 2) + oprot.writeString(self.value) + oprot.writeFieldEnd() + if self.annotation_type is not None: + oprot.writeFieldBegin('annotation_type', TType.I32, 3) + oprot.writeI32(self.annotation_type) + oprot.writeFieldEnd() + if self.host is not None: + oprot.writeFieldBegin('host', TType.STRUCT, 4) + self.host.write(oprot) + oprot.writeFieldEnd() + oprot.writeFieldStop() + oprot.writeStructEnd() + + def validate(self): + return + + + def __repr__(self): + L = ['%s=%r' % (key, value) + for key, value in self.__dict__.iteritems()] + return '%s(%s)' % (self.__class__.__name__, ', '.join(L)) + + def __eq__(self, other): + return isinstance(other, self.__class__) and self.__dict__ == other.__dict__ + + def __ne__(self, other): + return not (self == other) + +class Span: + """ + Attributes: + - trace_id + - name + - id + - parent_id + - annotations + - binary_annotations + """ + + thrift_spec = ( + None, # 0 + (1, TType.I64, 'trace_id', None, None, ), # 1 + None, # 2 + (3, TType.STRING, 'name', None, None, ), # 3 + (4, TType.I64, 'id', None, None, ), # 4 + (5, TType.I64, 'parent_id', None, None, ), # 5 + (6, TType.LIST, 'annotations', (TType.STRUCT,(Annotation, Annotation.thrift_spec)), None, ), # 6 + None, # 7 + (8, TType.LIST, 'binary_annotations', (TType.STRUCT,(BinaryAnnotation, BinaryAnnotation.thrift_spec)), None, ), # 8 + ) + + def __init__(self, trace_id=None, name=None, id=None, parent_id=None, annotations=None, binary_annotations=None,): + self.trace_id = trace_id + self.name = name + self.id = id + self.parent_id = parent_id + self.annotations = annotations + self.binary_annotations = binary_annotations + + def read(self, iprot): + if iprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and isinstance(iprot.trans, TTransport.CReadableTransport) and self.thrift_spec is not None and fastbinary is not None: + fastbinary.decode_binary(self, iprot.trans, (self.__class__, self.thrift_spec)) + return + iprot.readStructBegin() + while True: + (fname, ftype, fid) = iprot.readFieldBegin() + if ftype == TType.STOP: + break + if fid == 1: + if ftype == TType.I64: + self.trace_id = iprot.readI64(); + else: + iprot.skip(ftype) + elif fid == 3: + if ftype == TType.STRING: + self.name = iprot.readString(); + else: + iprot.skip(ftype) + elif fid == 4: + if ftype == TType.I64: + self.id = iprot.readI64(); + else: + iprot.skip(ftype) + elif fid == 5: + if ftype == TType.I64: + self.parent_id = iprot.readI64(); + else: + iprot.skip(ftype) + elif fid == 6: + if ftype == TType.LIST: + self.annotations = [] + (_etype3, _size0) = iprot.readListBegin() + for _i4 in xrange(_size0): + _elem5 = Annotation() + _elem5.read(iprot) + self.annotations.append(_elem5) + iprot.readListEnd() + else: + iprot.skip(ftype) + elif fid == 8: + if ftype == TType.LIST: + self.binary_annotations = [] + (_etype9, _size6) = iprot.readListBegin() + for _i10 in xrange(_size6): + _elem11 = BinaryAnnotation() + _elem11.read(iprot) + self.binary_annotations.append(_elem11) + iprot.readListEnd() + else: + iprot.skip(ftype) + else: + iprot.skip(ftype) + iprot.readFieldEnd() + iprot.readStructEnd() + + def write(self, oprot): + if oprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and self.thrift_spec is not None and fastbinary is not None: + oprot.trans.write(fastbinary.encode_binary(self, (self.__class__, self.thrift_spec))) + return + oprot.writeStructBegin('Span') + if self.trace_id is not None: + oprot.writeFieldBegin('trace_id', TType.I64, 1) + oprot.writeI64(self.trace_id) + oprot.writeFieldEnd() + if self.name is not None: + oprot.writeFieldBegin('name', TType.STRING, 3) + oprot.writeString(self.name) + oprot.writeFieldEnd() + if self.id is not None: + oprot.writeFieldBegin('id', TType.I64, 4) + oprot.writeI64(self.id) + oprot.writeFieldEnd() + if self.parent_id is not None: + oprot.writeFieldBegin('parent_id', TType.I64, 5) + oprot.writeI64(self.parent_id) + oprot.writeFieldEnd() + if self.annotations is not None: + oprot.writeFieldBegin('annotations', TType.LIST, 6) + oprot.writeListBegin(TType.STRUCT, len(self.annotations)) + for iter12 in self.annotations: + iter12.write(oprot) + oprot.writeListEnd() + oprot.writeFieldEnd() + if self.binary_annotations is not None: + oprot.writeFieldBegin('binary_annotations', TType.LIST, 8) + oprot.writeListBegin(TType.STRUCT, len(self.binary_annotations)) + for iter13 in self.binary_annotations: + iter13.write(oprot) + oprot.writeListEnd() + oprot.writeFieldEnd() + oprot.writeFieldStop() + oprot.writeStructEnd() + + def validate(self): + return + + + def __repr__(self): + L = ['%s=%r' % (key, value) + for key, value in self.__dict__.iteritems()] + return '%s(%s)' % (self.__class__.__name__, ', '.join(L)) + + def __eq__(self, other): + return isinstance(other, self.__class__) and self.__dict__ == other.__dict__ + + def __ne__(self, other): + return not (self == other) diff --git a/src/blkin/babeltrace-plugins/zipkin/src/zipkin_logic/zipkin_client.py b/src/blkin/babeltrace-plugins/zipkin/src/zipkin_logic/zipkin_client.py new file mode 100644 index 000000000..28118facb --- /dev/null +++ b/src/blkin/babeltrace-plugins/zipkin/src/zipkin_logic/zipkin_client.py @@ -0,0 +1,70 @@ +#!/usr/bin/python + +from scribe_client import ScribeClient +from trace import Annotation, Trace, Endpoint +from collections import defaultdict +from formatters import base64_thrift_formatter + + +class ZipkinClient(ScribeClient): + + DEFAULT_END_ANNOTATIONS = ("ss", "cr", "end") + + def __init__(self, port, host): + super(ZipkinClient, self).__init__(port, host) + self._annotations_for_trace = defaultdict(list) + + def create_trace(self, event): + service = event["trace_name"] + trace_id = event["trace_id"] + span_id = event["span_id"] + parent_span = event["parent_span_id"] + if parent_span == 0: + parent_span = None + trace = Trace(service, trace_id, span_id, parent_span) + return trace + + def create_annotation(self, event, kind): + if kind == "keyval_string": + key = event["key"] + val = event["val"] + annotation = Annotation.string(key, val) + elif kind == "keyval_integer": + key = event["key"] + val = str(event["val"]) + annotation = Annotation.string(key, val) + elif kind == "timestamp": + timestamp = event.timestamp + #timestamp has different digit length + timestamp = str(timestamp) + timestamp = timestamp[:-3] + event_name = event["event"] + annotation = Annotation.timestamp(event_name, int(timestamp)) + + # create and set endpoint + port = event["port_no"] + service = event["service_name"] + ip = event["ip"] + endpoint = Endpoint(ip, int(port), service) + annotation.endpoint = endpoint + + print annotation + return annotation + + def record(self, trace, annotation): + self.scribe_log(trace, [annotation]) + ''' + trace_key = (trace.trace_id, trace.span_id) + self._annotations_for_trace[trace_key].append(annotation) + if (annotation.name in self.DEFAULT_END_ANNOTATIONS): + saved_annotations = self._annotations_for_trace[trace_key] + del self._annotations_for_trace[trace_key] + self.scribe_log(trace, saved_annotations) + print "Record event" + ''' + + def scribe_log(self, trace, annotations): + trace._endpoint = None + message = base64_thrift_formatter(trace, annotations) + category = 'zipkin' + return self.log(category, message) diff --git a/src/blkin/babeltrace-plugins/zipkin/zipkin_trace.h b/src/blkin/babeltrace-plugins/zipkin/zipkin_trace.h new file mode 100644 index 000000000..4abc87b87 --- /dev/null +++ b/src/blkin/babeltrace-plugins/zipkin/zipkin_trace.h @@ -0,0 +1,67 @@ +/* + * Zipkin lttng-ust tracepoint provider. + */ + +#undef TRACEPOINT_PROVIDER +#define TRACEPOINT_PROVIDER zipkin + +#undef TRACEPOINT_INCLUDE +#define TRACEPOINT_INCLUDE "./zipkin_trace.h" + +#if !defined(_ZIPKIN_H) || defined(TRACEPOINT_HEADER_MULTI_READ) +#define _ZIPKIN_H + +#include <lttng/tracepoint.h> + +TRACEPOINT_EVENT( + zipkin, + keyval, + TP_ARGS(char *, service, char *, trace_name, + int, port, char *, ip, long, trace, + long, span, long, parent_span, + char *, key, char *, val ), + + TP_FIELDS( + ctf_string(trace_name, trace_name) + ctf_string(service_name, service) + ctf_integer(int, port_no, port) + ctf_string(ip, ip) + ctf_integer(long, trace_id, trace) + ctf_integer(long, span_id, span) + ctf_integer(long, parent_span_id, parent_span) + ctf_string(key, key) + ctf_string(val, val) + ) +) +TRACEPOINT_LOGLEVEL( + zipkin, + keyval, + TRACE_WARNING) + + +TRACEPOINT_EVENT( + zipkin, + timestamp, + TP_ARGS(char *, service, char *, trace_name, + int, port, char *, ip, long, trace, + long, span, long, parent_span, + char *, event), + + TP_FIELDS( + ctf_string(trace_name, trace_name) + ctf_string(service_name, service) + ctf_integer(int, port_no, port) + ctf_string(ip, ip) + ctf_integer(long, trace_id, trace) + ctf_integer(long, span_id, span) + ctf_integer(long, parent_span_id, parent_span) + ctf_string(event, event) + ) +) +TRACEPOINT_LOGLEVEL( + zipkin, + timestamp, + TRACE_WARNING) +#endif /* _ZIPKIN_H */ + +#include <lttng/tracepoint-event.h> diff --git a/src/blkin/blkin-lib/CMakeLists.txt b/src/blkin/blkin-lib/CMakeLists.txt new file mode 100644 index 000000000..d2e1d0f73 --- /dev/null +++ b/src/blkin/blkin-lib/CMakeLists.txt @@ -0,0 +1,18 @@ +include_directories(.) + +#blkin +set(blkin_srcs + zipkin_c.c + tp.c +) +add_library(blkin ${blkin_srcs}) +set_target_properties(blkin PROPERTIES POSITION_INDEPENDENT_CODE ON) +target_link_libraries(blkin dl ${LTTNG_LIBRARIES}) + +set(blkin_headers + zipkin_c.h + zipkin_trace.h + ztracer.hpp +) + +add_subdirectory(tests) diff --git a/src/blkin/blkin-lib/Makefile b/src/blkin/blkin-lib/Makefile new file mode 100644 index 000000000..52852f449 --- /dev/null +++ b/src/blkin/blkin-lib/Makefile @@ -0,0 +1,92 @@ +# Copyright 2014 Marios Kogias <marioskogias@gmail.com> +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# 1. Redistributions of source code must retain the above +# copyright notice, this list of conditions and the following +# disclaimer. +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials +# provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESS +# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +.PHONY: default clean distclean run run_c run_pp + +MAJOR=0 +MINOR=1 +LIBS= -ldl -llttng-ust +DLIB=libblkin + +LIB_DIR=$(shell pwd) +TEST_DIR=$(shell pwd)/tests +prefix= /usr/local +libdir= $(prefix)/lib +incdir= $(prefix)/include + +H_FILES= zipkin_c.h zipkin_trace.h ztracer.hpp + +default: $(DLIB).so test testpp testppp + +$(DLIB).so: $(DLIB).$(MAJOR).so + ln -sf $< $@ + +$(DLIB).$(MAJOR).so: $(DLIB).$(MAJOR).$(MINOR).so + ln -sf $< $@ + +$(DLIB).$(MAJOR).$(MINOR).so: zipkin_c.o tp.o + g++ -shared -o $@ $^ $(LIBS) + +zipkin_c.o: zipkin_c.c zipkin_c.h zipkin_trace.h + gcc -I. -Wall -fpic -g -c -o $@ $< + +tp.o: tp.c zipkin_trace.h + gcc -I. -fpic -g -c -o $@ $< + +test: $(TEST_DIR)/test.c $(DLIB).so + make -C tests test + +testpp: $(TEST_DIR)/test.cc $(DLIB).so + make -C tests testpp + +testppp: $(TEST_DIR)/test_p.cc $(DLIB).so + make -C tests testppp + +run_c: + make -C tests run_c + +run_pp: + make -C tests run_pp + +run_ppp: + make -C tests run_ppp + +run: run_c run_pp + +install: + install -m 644 $(DLIB).$(MAJOR).$(MINOR).so $(DESTDIR)/$(libdir) + cp -P $(DLIB).$(MAJOR).so $(DESTDIR)/$(libdir) + cp -P $(DLIB).so $(DESTDIR)/$(libdir) + install -m 644 $(H_FILES) $(DESTDIR)/$(incdir) + +clean: + rm -f *.o *.so + make -C tests clean + +distclean: clean + rm -f socket diff --git a/src/blkin/blkin-lib/tests/CMakeLists.txt b/src/blkin/blkin-lib/tests/CMakeLists.txt new file mode 100644 index 000000000..d69cec3da --- /dev/null +++ b/src/blkin/blkin-lib/tests/CMakeLists.txt @@ -0,0 +1,15 @@ +#test +add_executable(testc test.c) +target_link_libraries(testc blkin lttng-ust) +add_test(NAME testc COMMAND $<TARGET_FILE:testc>) + +#testpp +add_executable(testpp test.cc) +set_target_properties(testpp PROPERTIES COMPILE_FLAGS "-std=c++11") +target_link_libraries(testpp blkin lttng-ust pthread) +add_test(NAME testpp COMMAND $<TARGET_FILE:testpp>) + +#testppp +add_executable(testppp test_p.cc) +target_link_libraries(testppp blkin lttng-ust) +add_test(NAME testppp COMMAND $<TARGET_FILE:testppp>) diff --git a/src/blkin/blkin-lib/tests/Makefile b/src/blkin/blkin-lib/tests/Makefile new file mode 100644 index 000000000..bed3fc869 --- /dev/null +++ b/src/blkin/blkin-lib/tests/Makefile @@ -0,0 +1,55 @@ +# Copyright 2014 Marios Kogias <marioskogias@gmail.com> +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# 1. Redistributions of source code must retain the above +# copyright notice, this list of conditions and the following +# disclaimer. +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials +# provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESS +# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +.PHONY: default clean distclean run run_c run_pp + +LIB_DIR=$(shell pwd)/.. +DLIB=$(LIB_DIR)/libblkin + +test: test.c $(DLIB).so + gcc test.c -o test -g -I$(LIB_DIR) -L$(LIB_DIR) -lblkin + +testpp: test.cc $(DLIB).so + LD_LIBRARY_PATH=$(LIB_DIR) g++ $< -o testpp -std=c++11 -g -I$(LIB_DIR) -L$(LIB_DIR) -lblkin -lpthread + +testppp: test_p.cc $(DLIB).so + LD_LIBRARY_PATH=$(LIB_DIR) g++ $< -o testppp -g -I$(LIB_DIR) -L$(LIB_DIR) -lblkin + +run_c: + LD_LIBRARY_PATH=$(LIB_DIR) ./test + +run_pp: + LD_LIBRARY_PATH=$(LIB_DIR) ./testpp + +run_ppp: + LD_LIBRARY_PATH=$(LIB_DIR) ./testppp + +run: run_c run_pp + +clean: + rm -f *.o *.so test testpp testppp socket diff --git a/src/blkin/blkin-lib/tests/test.c b/src/blkin/blkin-lib/tests/test.c new file mode 100644 index 000000000..2cabd99bf --- /dev/null +++ b/src/blkin/blkin-lib/tests/test.c @@ -0,0 +1,200 @@ +/* + * Copyright 2014 Marios Kogias <marioskogias@gmail.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * In this example we have 2 processes communicating over a unix socket. + * We are going to trace the communication with our library + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include <zipkin_c.h> + +#define SOCK_PATH "/tmp/socket" + +struct message { + char actual_message[20]; + struct blkin_trace_info trace_info; +}; + +void process_a() +{ + int i, r; + printf("I am process A: %d\n", getpid()); + + r = blkin_init(); + if (r < 0) { + fprintf(stderr, "Could not initialize blkin\n"); + exit(1); + } + + /*initialize endpoint*/ + struct blkin_endpoint endp; + blkin_init_endpoint(&endp, "10.0.0.1", 5000, "service a"); + + struct blkin_trace trace; + struct blkin_annotation ant; + struct message msg = {.actual_message = "message"}; + char ack; + + /*create and bind socket*/ + int s, s2, len; + socklen_t t; + struct sockaddr_un local, remote; + + if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + perror("socket"); + exit(1); + } + + local.sun_family = AF_UNIX; + strcpy(local.sun_path, SOCK_PATH); + unlink(local.sun_path); + len = strlen(local.sun_path) + sizeof(local.sun_family); + if (bind(s, (struct sockaddr *)&local, len) == -1) { + perror("bind"); + exit(1); + } + + if (listen(s, 5) == -1) { + perror("listen"); + exit(1); + } + + printf("Waiting for a connection...\n"); + t = sizeof(remote); + if ((s2 = accept(s, (struct sockaddr *)&remote, &t)) == -1) { + perror("accept"); + exit(1); + } + + printf("Connected.\n"); + + for (i=0;i<10;i++) { + + /*create trace*/ + blkin_init_new_trace(&trace, "process a", &endp); + + blkin_init_timestamp_annotation(&ant, "start", &endp); + blkin_record(&trace, &ant); + + /*set trace fields to message*/ + blkin_get_trace_info(&trace, &msg.trace_info); + + /*send*/ + send(s2, &msg, sizeof(struct message), 0); + + /*wait for ack*/ + recv(s2, &ack, 1, 0); + + /*create annotation and log*/ + blkin_init_timestamp_annotation(&ant, "end", &endp); + blkin_record(&trace, &ant); + } + close(s2); +} + +void process_b() +{ + int i, r; + printf("I am process B: %d\n", getpid()); + + r = blkin_init(); + if (r < 0) { + fprintf(stderr, "Could not initialize blkin\n"); + exit(1); + } + /*initialize endpoint*/ + struct blkin_endpoint endp; + blkin_init_endpoint(&endp, "10.0.0.2", 5001, "service b"); + + struct blkin_trace trace; + struct blkin_annotation ant; + struct message msg; + int s, len; + struct sockaddr_un remote; + + /*Connect*/ + if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + perror("socket"); + exit(1); + } + + printf("Trying to connect...\n"); + + remote.sun_family = AF_UNIX; + strcpy(remote.sun_path, SOCK_PATH); + len = strlen(remote.sun_path) + sizeof(remote.sun_family); + if (connect(s, (struct sockaddr *)&remote, len) == -1) { + perror("connect"); + exit(1); + } + + printf("Connected.\n"); + + for (i=0;i<10;i++) { + recv(s, &msg, sizeof(struct message), 0); + + /*create child trace*/ + blkin_init_child_info(&trace, &msg.trace_info, &endp, "process b"); + + /*create annotation and log*/ + blkin_init_timestamp_annotation(&ant, "start", &endp); + blkin_record(&trace, &ant); + + /*Process...*/ + usleep(10); + printf("Message received %s\n", msg.actual_message); + + /*create annotation and log*/ + blkin_init_timestamp_annotation(&ant, "end", &endp); + blkin_record(&trace, &ant); + + /*send ack*/ + send(s, "*", 1, 0); + } +} + + +int main() +{ + if (fork()){ + process_a(); + exit(0); + } + else{ + process_b(); + exit(0); + } +} diff --git a/src/blkin/blkin-lib/tests/test.cc b/src/blkin/blkin-lib/tests/test.cc new file mode 100644 index 000000000..f93597dd3 --- /dev/null +++ b/src/blkin/blkin-lib/tests/test.cc @@ -0,0 +1,204 @@ +/* + * Copyright 2014 Marios Kogias <marioskogias@gmail.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include <thread> +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <ztracer.hpp> +#include <iostream> + +#define SOCK_PATH "socket" + +struct message { + int actual_message; + struct blkin_trace_info trace_info; + message(int s) : actual_message(s) {}; + message() {} +}; + +class Parent { + private: + int s, s2; + ZTracer::Endpoint e; + public: + Parent() : e("0.0.0.0", 1, "parent") + { + connect(); + } + void operator()() + { + struct sockaddr_un remote; + int t; + std::cout << "I am parent process : " << getpid() << std::endl; + + /* Wait for connection */ + t = sizeof(remote); + if ((s2 = accept(s, (struct sockaddr *)&remote, (socklen_t *)&t)) == -1) { + std::cerr << "accept" << std::endl; + exit(1); + } + + std::cerr << "Connected" << std::endl; + + for (int i=0;i<10;i++) { + /*Init trace*/ + ZTracer::Trace tr("parent process", &e); + + process(tr); + + wait_response(); + + /*Log received*/ + tr.event("parent end"); + } + } + + void process(ZTracer::Trace &tr) + { + struct message msg(rand()); + /*Annotate*/ + tr.event("parent start"); + /*Set trace info to the message*/ + msg.trace_info = *tr.get_info(); + + /*send*/ + send(s2, &msg, sizeof(struct message), 0); + } + + void wait_response() + { + char ack; + recv(s2, &ack, 1, 0); + } + + void connect() + { + /*create and bind socket*/ + int len; + struct sockaddr_un local; + + if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + std::cerr << "socket" << std::endl; + exit(1); + } + + local.sun_family = AF_UNIX; + strcpy(local.sun_path, SOCK_PATH); + unlink(local.sun_path); + len = strlen(local.sun_path) + sizeof(local.sun_family); + if (bind(s, (struct sockaddr *)&local, len) == -1) { + std::cerr << "bind" << std::endl; + exit(1); + } + + if (listen(s, 5) == -1) { + std::cerr << "listen" << std::endl; + exit(1); + } + + std::cout << "Waiting for a connection..." << std::endl; + } + +}; + +class Child { + private: + int s; + ZTracer::Endpoint e; + public: + Child() : e("0.0.0.1", 2, "child") + { + } + void operator()() + { + /*Connect to the socket*/ + soc_connect(); + + for (int i=0;i<10;i++) + process(); + } + + void process() + { + struct message msg; + recv(s, &msg, sizeof(struct message), 0); + + ZTracer::Trace tr("Child process", &e, &msg.trace_info, true); + tr.event("child start"); + + usleep(10); + std::cout << "Message received : " << msg.actual_message << ::std::endl; + tr.event("child end"); + + send(s, "*", 1, 0); + } + + + void soc_connect() + { + int len; + struct sockaddr_un remote; + + if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + std::cerr << "socket" << std::endl; + exit(1); + } + + std::cout << "Trying to connect...\n" << std::endl; + + remote.sun_family = AF_UNIX; + strcpy(remote.sun_path, SOCK_PATH); + len = strlen(remote.sun_path) + sizeof(remote.sun_family); + if (connect(s, (struct sockaddr *)&remote, len) == -1) { + std::cerr << "connect" << std::endl;; + exit(1); + } + + std::cout << "Connected" << std::endl; + } + +}; +int main(int argc, const char *argv[]) +{ + int r = ZTracer::ztrace_init(); + if (r < 0) { + std::cout << "Error initializing blkin" << std::endl; + return -1; + } + Parent p; + Child c; + std::thread workerThread1(p); + std::thread workerThread2(c); + workerThread1.join(); + workerThread2.join(); + + return 0; +} diff --git a/src/blkin/blkin-lib/tests/test_p.cc b/src/blkin/blkin-lib/tests/test_p.cc new file mode 100644 index 000000000..ec59da3b6 --- /dev/null +++ b/src/blkin/blkin-lib/tests/test_p.cc @@ -0,0 +1,210 @@ +/* + * Copyright 2014 Marios Kogias <marioskogias@gmail.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <ztracer.hpp> +#include <iostream> +#include <cstdlib> + +#define SOCK_PATH "socket" + +struct message { + int actual_message; + struct blkin_trace_info trace_info; + message(int s) : actual_message(s) {}; + message() {} +}; + +class Parent { + private: + int s, s2; + ZTracer::Endpoint e; + public: + Parent() : e("0.0.0.0", 1, "parent") + { + connect(); + } + void operator()() + { + struct sockaddr_un remote; + int t; + std::cout << "I am parent process : " << getpid() << std::endl; + + /* Wait for connection */ + t = sizeof(remote); + if ((s2 = accept(s, (struct sockaddr *)&remote, (socklen_t *)&t)) == -1) { + std::cerr << "accept" << std::endl; + exit(1); + } + + std::cerr << "Connected" << std::endl; + + for (int i=0;i<10;i++) { + /*Init trace*/ + ZTracer::Trace tr("parent process", &e); + process(tr); + + wait_response(); + + /*Log received*/ + tr.event("parent end"); + } + } + + void process(ZTracer::Trace &tr) + { + struct message msg(rand()); + /*Annotate*/ + tr.event("parent start"); + /*Set trace info to the message*/ + msg.trace_info = *tr.get_info(); + + /*send*/ + send(s2, &msg, sizeof(struct message), 0); + } + + void wait_response() + { + char ack; + recv(s2, &ack, 1, 0); + } + + void connect() + { + /*create and bind socket*/ + int len; + struct sockaddr_un local; + + if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + std::cerr << "socket" << std::endl; + exit(1); + } + + local.sun_family = AF_UNIX; + strcpy(local.sun_path, SOCK_PATH); + unlink(local.sun_path); + len = strlen(local.sun_path) + sizeof(local.sun_family); + if (bind(s, (struct sockaddr *)&local, len) == -1) { + std::cerr << "bind" << std::endl; + exit(1); + } + + if (listen(s, 5) == -1) { + std::cerr << "listen" << std::endl; + exit(1); + } + + std::cout << "Waiting for a connection..." << std::endl; + } + +}; + +class Child { + private: + int s; + ZTracer::Endpoint e; + public: + Child() : e("0.0.0.1", 2, "child") + { + } + void operator()() + { + /*Connect to the socket*/ + soc_connect(); + + for (int i=0;i<10;i++) + process(); + } + + void process() + { + struct message msg; + recv(s, &msg, sizeof(struct message), 0); + + ZTracer::Trace tr("Child process", &e, &msg.trace_info, true); + tr.event("child start"); + + usleep(10); + std::cout << "Message received : " << msg.actual_message << ::std::endl; + tr.event("child end"); + + send(s, "*", 1, 0); + } + + + void soc_connect() + { + int len; + struct sockaddr_un remote; + + if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + std::cerr << "socket" << std::endl; + exit(1); + } + + std::cout << "Trying to connect...\n" << std::endl; + + remote.sun_family = AF_UNIX; + strcpy(remote.sun_path, SOCK_PATH); + len = strlen(remote.sun_path) + sizeof(remote.sun_family); + if (connect(s, (struct sockaddr *)&remote, len) == -1) { + std::cerr << "connect" << std::endl;; + exit(1); + } + + std::cout << "Connected" << std::endl; + } + +}; +int main(int argc, const char *argv[]) +{ + if (fork()) { + int r = ZTracer::ztrace_init(); + if (r < 0) { + std::cout << "Error initializing blkin" << std::endl; + exit(1); + } + Parent p; + p(); + exit(0); + } else { + int r = ZTracer::ztrace_init(); + if (r < 0) { + std::cout << "Error initializing blkin" << std::endl; + exit(1); + } + Child c; + c(); + exit(0); + } + return 0; +} diff --git a/src/blkin/blkin-lib/tp.c b/src/blkin/blkin-lib/tp.c new file mode 100644 index 000000000..e72177e57 --- /dev/null +++ b/src/blkin/blkin-lib/tp.c @@ -0,0 +1,35 @@ +/* + * tp.c + * + * Copyright (c) 2011 Mathieu Desnoyers <mathieu.desnoyers@efficios.com> + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Defining macro creates the code objects of the traceprobes, only do + * it once per file + */ +#define TRACEPOINT_CREATE_PROBES +/* + * The header containing our TRACEPOINT_EVENTs. + */ +#include <zipkin_trace.h> diff --git a/src/blkin/blkin-lib/zipkin_c.c b/src/blkin/blkin-lib/zipkin_c.c new file mode 100644 index 000000000..a68182b55 --- /dev/null +++ b/src/blkin/blkin-lib/zipkin_c.c @@ -0,0 +1,356 @@ +/* + * Copyright 2014 Marios Kogias <marioskogias@gmail.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "zipkin_c.h" +#include <pthread.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> + +#define TRACEPOINT_DEFINE +#include <zipkin_trace.h> + +const char *default_ip = "NaN"; +const char *default_name = "NoName"; + +const char* const CLIENT_SEND = "cs"; +const char* const CLIENT_RECV = "cr"; +const char* const SERVER_SEND = "ss"; +const char* const SERVER_RECV = "sr"; +const char* const WIRE_SEND = "ws"; +const char* const WIRE_RECV = "wr"; +const char* const CLIENT_SEND_FRAGMENT = "csf"; +const char* const CLIENT_RECV_FRAGMENT = "crf"; +const char* const SERVER_SEND_FRAGMENT = "ssf"; +const char* const SERVER_RECV_FRAGMENT = "srf"; + +static int64_t random_big() +{ + int64_t a; + a = rand(); + a = a << 32; + int b = rand(); + a = a + b; + if (a<0) + a = !a; + return a; +} + +int blkin_init() +{ + static pthread_mutex_t blkin_init_mutex = PTHREAD_MUTEX_INITIALIZER; + static int initialized = 0; + + /* + * Initialize srand with sth appropriete + * time is not good for archipelago: several deamons -> same timstamp + */ + pthread_mutex_lock(&blkin_init_mutex); + if (!initialized) { + int inf, seed; + inf = open("/dev/urandom", O_RDONLY); //file descriptor 1 + read(inf, &seed, sizeof(int)); + close(inf); + srand(seed); + initialized = 1; + } + pthread_mutex_unlock(&blkin_init_mutex); + return 0; +} + +int blkin_init_new_trace(struct blkin_trace *new_trace, const char *service, + const struct blkin_endpoint *endpoint) +{ + int res; + if (!new_trace) { + res = -EINVAL; + goto OUT; + } + new_trace->name = service; + blkin_init_trace_info(&(new_trace->info)); + new_trace->endpoint = endpoint; + res = 0; + +OUT: + return res; +} + +void blkin_init_trace_info(struct blkin_trace_info *trace_info) +{ + trace_info->span_id = trace_info->trace_id = random_big(); + trace_info->parent_span_id = 0; +} + +int blkin_init_child_info(struct blkin_trace *child, + const struct blkin_trace_info *parent_info, + const struct blkin_endpoint *endpoint, + const char *child_name) +{ + int res; + if ((!child) || (!parent_info) || (!endpoint)){ + res = -EINVAL; + goto OUT; + } + child->info.trace_id = parent_info->trace_id; + child->info.span_id = random_big(); + child->info.parent_span_id = parent_info->span_id; + child->name = child_name; + child->endpoint = endpoint; + res = 0; + +OUT: + return res; +} + +int blkin_init_child(struct blkin_trace *child, + const struct blkin_trace *parent, + const struct blkin_endpoint *endpoint, + const char *child_name) +{ + int res; + if (!parent) { + res = -EINVAL; + goto OUT; + } + if (!endpoint) + endpoint = parent->endpoint; + if (blkin_init_child_info(child, &parent->info, endpoint, child_name) != 0){ + res = -EINVAL; + goto OUT; + } + res = 0; + +OUT: + return res; +} + +int blkin_init_endpoint(struct blkin_endpoint *endp, const char *ip, + int16_t port, const char *name) +{ + int res; + if (!endp){ + res = -EINVAL; + goto OUT; + } + if (!ip) + ip = default_ip; + + endp->ip = ip; + endp->port = port; + endp->name = name; + res = 0; + +OUT: + return res; +} + +int blkin_init_string_annotation(struct blkin_annotation *annotation, + const char *key, const char *val, const struct blkin_endpoint *endpoint) +{ + int res; + if ((!annotation) || (!key) || (!val)){ + res = -EINVAL; + goto OUT; + } + annotation->type = ANNOT_STRING; + annotation->key = key; + annotation->val_str = val; + annotation->endpoint = endpoint; + res = 0; + +OUT: + return res; +} + +int blkin_init_integer_annotation(struct blkin_annotation *annotation, + const char *key, int64_t val, const struct blkin_endpoint *endpoint) +{ + int res; + if ((!annotation) || (!key)) { + res = -EINVAL; + goto OUT; + } + annotation->type = ANNOT_INTEGER; + annotation->key = key; + annotation->val_int = val; + annotation->endpoint = endpoint; + res = 0; + +OUT: + return res; +} + +int blkin_init_timestamp_annotation(struct blkin_annotation *annotation, + const char *event, const struct blkin_endpoint *endpoint) +{ + int res; + if ((!annotation) || (!event)){ + res = -EINVAL; + goto OUT; + } + annotation->type = ANNOT_TIMESTAMP; + annotation->val_str = event; + annotation->endpoint = endpoint; + res = 0; + +OUT: + return res; +} + +int blkin_record(const struct blkin_trace *trace, + const struct blkin_annotation *annotation) +{ + int res; + if (!annotation || !trace || !trace->name) { + res = -EINVAL; + goto OUT; + } + + const struct blkin_endpoint *endpoint = + annotation->endpoint ? : trace->endpoint; + if (!endpoint || !endpoint->ip || !endpoint->name) { + res = -EINVAL; + goto OUT; + } + + if (annotation->type == ANNOT_STRING) { + if ((!annotation->key) || (!annotation->val_str)) { + res = -EINVAL; + goto OUT; + } + tracepoint(zipkin, keyval_string, trace->name, + endpoint->name, endpoint->port, endpoint->ip, + trace->info.trace_id, trace->info.span_id, + trace->info.parent_span_id, + annotation->key, annotation->val_str); + } + else if (annotation->type == ANNOT_INTEGER) { + if (!annotation->key) { + res = -EINVAL; + goto OUT; + } + tracepoint(zipkin, keyval_integer, trace->name, + endpoint->name, endpoint->port, endpoint->ip, + trace->info.trace_id, trace->info.span_id, + trace->info.parent_span_id, + annotation->key, annotation->val_int); + } + else { + if (!annotation->val_str) { + res = -EINVAL; + goto OUT; + } + tracepoint(zipkin, timestamp , trace->name, + endpoint->name, endpoint->port, endpoint->ip, + trace->info.trace_id, trace->info.span_id, + trace->info.parent_span_id, + annotation->val_str); + } + res = 0; +OUT: + return res; +} + +int blkin_get_trace_info(const struct blkin_trace *trace, + struct blkin_trace_info *info) +{ + int res; + if ((!trace) || (!info)){ + res = -EINVAL; + goto OUT; + } + + res = 0; + *info = trace->info; +OUT: + return res; +} + +int blkin_set_trace_info(struct blkin_trace *trace, + const struct blkin_trace_info *info) +{ + int res; + if ((!trace) || (!info)){ + res = -EINVAL; + goto OUT; + } + + res = 0; + trace->info = *info; +OUT: + return res; +} + +int blkin_set_trace_properties(struct blkin_trace *trace, + const struct blkin_trace_info *info, + const char *name, + const struct blkin_endpoint *endpoint) +{ + int res; + if ((!trace) || (!info) || (!endpoint) || (!name)){ + res = -EINVAL; + goto OUT; + } + + res = 0; + trace->info = *info; + trace->name = name; + trace->endpoint = endpoint; + +OUT: + return res; +} + +int blkin_pack_trace_info(const struct blkin_trace_info *info, + struct blkin_trace_info_packed *pinfo) +{ + if (!info || !pinfo) { + return -EINVAL; + } + + pinfo->trace_id = __cpu_to_be64(info->trace_id); + pinfo->span_id = __cpu_to_be64(info->span_id); + pinfo->parent_span_id = __cpu_to_be64(info->parent_span_id); + + return 0; +} + +int blkin_unpack_trace_info(const struct blkin_trace_info_packed *pinfo, + struct blkin_trace_info *info) +{ + if (!info || !pinfo) { + return -EINVAL; + } + + info->trace_id = __be64_to_cpu(pinfo->trace_id); + info->span_id = __be64_to_cpu(pinfo->span_id); + info->parent_span_id = __be64_to_cpu(pinfo->parent_span_id); + + return 0; +} diff --git a/src/blkin/blkin-lib/zipkin_c.h b/src/blkin/blkin-lib/zipkin_c.h new file mode 100644 index 000000000..77b5bc6d7 --- /dev/null +++ b/src/blkin/blkin-lib/zipkin_c.h @@ -0,0 +1,334 @@ +/* + * Copyright 2014 Marios Kogias <marioskogias@gmail.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef ZIPKIN_C_H_ +#define ZIPKIN_C_H_ + +#include <stdint.h> +#include <asm/byteorder.h> + +#define BLKIN_TIMESTAMP(trace, endp, event) \ + do { \ + struct blkin_annotation __annot; \ + blkin_init_timestamp_annotation(&__annot, event, endp); \ + blkin_record(trace, &__annot); \ + } while (0); + +#define BLKIN_KEYVAL_STRING(trace, endp, key, val) \ + do { \ + struct blkin_annotation __annot; \ + blkin_init_string_annotation(&__annot, key, val, endp); \ + blkin_record(trace, &__annot); \ + } while (0); + +#define BLKIN_KEYVAL_INTEGER(trace, endp, key, val) \ + do { \ + struct blkin_annotation __annot; \ + blkin_init_integer_annotation(&__annot, key, val, endp);\ + blkin_record(trace, &__annot); \ + } while (0); + +/** + * Core annotations used by Zipkin used to denote the beginning and end of + * client and server spans. + * For more information refer to + * https://github.com/openzipkin/zipkin/blob/master/zipkin-thrift/src/main/thrift/com/twitter/zipkin/zipkinCore.thrift + */ +extern const char* const CLIENT_SEND; +extern const char* const CLIENT_RECV; +extern const char* const SERVER_SEND; +extern const char* const SERVER_RECV; +extern const char* const WIRE_SEND; +extern const char* const WIRE_RECV; +extern const char* const CLIENT_SEND_FRAGMENT; +extern const char* const CLIENT_RECV_FRAGMENT; +extern const char* const SERVER_SEND_FRAGMENT; +extern const char* const SERVER_RECV_FRAGMENT; + +/** + * @struct blkin_endpoint + * Information about an endpoint of our instrumented application where + * annotations take place + */ +struct blkin_endpoint { + const char *ip; + int16_t port; + const char *name; +}; + +/** + * @struct blkin_trace_info + * The information exchanged between different layers offering the needed + * trace semantics + */ +struct blkin_trace_info { + int64_t trace_id; + int64_t span_id; + int64_t parent_span_id; +}; + +/** + * @struct blkin_trace_info_packed + * + * Packed version of the struct blkin_trace_info. Usefull when sending over + * network. + * + */ +struct blkin_trace_info_packed { + __be64 trace_id; + __be64 span_id; + __be64 parent_span_id; +} __attribute__((packed)); + + +/** + * @struct blkin_trace + * Struct used to define the context in which an annotation happens + */ +struct blkin_trace { + const char *name; + struct blkin_trace_info info; + const struct blkin_endpoint *endpoint; +}; + +/** + * @typedef blkin_annotation_type + * There are 2 kinds of annotation key-val and timestamp + */ +typedef enum { + ANNOT_STRING = 0, + ANNOT_INTEGER, + ANNOT_TIMESTAMP +} blkin_annotation_type; + +/** + * @struct blkin_annotation + * Struct carrying information about an annotation. This information can either + * be key-val or that a specific event happened + */ +struct blkin_annotation { + blkin_annotation_type type; + const char *key; + union { + const char *val_str; + int64_t val_int; + }; + const struct blkin_endpoint *endpoint; +}; + +/** + * Initialize the zipkin library. + * + * @return 0 on success + */ +int blkin_init(); + +/** + * Initialize a new blkin_trace with the information given. The new trace will + * have no parent so the parent id will be zero. + * + * @param new_trace the blkin_trace to be initialized + * @param name the trace's name + * @param endpoint a pointer to a blkin_endpoint struct that contains + * info about where the specific trace takes place + * + * @returns 0 on success or negative error code + */ +int blkin_init_new_trace(struct blkin_trace *new_trace, const char *name, + const struct blkin_endpoint *endpoint); + +/** + * Initialize blkin_trace_info for a root span. The new trace will + * have no parent so the parent id will be zero, and the id and trace id will + * be the same. + * + * @param trace_info the blkin_trace_info to be initialized + */ +void blkin_init_trace_info(struct blkin_trace_info *trace_info); + +/** + * Initialize a blkin_trace as a child of the given parent + * bkin_trace. The child trace will have the same trace_id, new + * span_id and parent_span_id its parent's span_id. + * + * @param child the blkin_trace to be initialized + * @param parent the parent blkin_trace + * @param child_name the blkin_trace name of the child + * + * @returns 0 on success or negative error code + */ +int blkin_init_child(struct blkin_trace *child, + const struct blkin_trace *parent, + const struct blkin_endpoint *endpoint, + const char *child_name); + +/** + * Initialize a blkin_trace struct and set the blkin_trace_info field to be + * child of the given blkin_trace_info. This means + * Same trace_id + * Different span_id + * Child's parent_span_id == parent's span_id + * + * @param child the new child blkin_trace_info + * @param info the parent's blkin_trace_info struct + * @param child_name the blkin_trace struct name field + * + * @returns 0 on success or negative error code + */ +int blkin_init_child_info(struct blkin_trace *child, + const struct blkin_trace_info *info, + const struct blkin_endpoint *endpoint, + const char *child_name); + +/** + * Initialize a blkin_endpoint struct with the information given + * + * @param endp the endpoint to be initialized + * @param ip the ip address of the specific endpoint + * @param port the TCP/UDP port of the specific endpoint + * @param name the name of the service running on the specific endpoint + * + * @returns 0 on success or negative error code + */ +int blkin_init_endpoint(struct blkin_endpoint *endpoint, + const char *ip, int16_t port, const char *name); + +/** + * Initialize a key-value blkin_annotation + * + * @param annotation the annotation to be initialized + * @param key the annotation's key + * @param val the annotation's string value + * @param endpoint where did this annotation occured + * + * @returns 0 on success or negative error code + */ +int blkin_init_string_annotation(struct blkin_annotation *annotation, + const char *key, const char *val, + const struct blkin_endpoint *endpoint); +/** + * Initialize a key-value blkin_annotation + * + * @param annotation the annotation to be initialized + * @param key the annotation's key + * @param val the annotation's int value + * @param endpoint where did this annotation occured + * + * @returns 0 on success or negative error code + */ + +int blkin_init_integer_annotation(struct blkin_annotation *annotation, + const char *key, int64_t val, + const struct blkin_endpoint *endpoint); + +/** + * Initialize a timestamp blkin_annotation + * + * @param annotation the annotation to be initialized + * @param event the event happened to be annotated + * @param endpoint where did this annotation occured + * + * @returns 0 on success or negative error code + */ + +int blkin_init_timestamp_annotation(struct blkin_annotation *annot, + const char *event, + const struct blkin_endpoint *endpoint); + +/** + * Log an annotation in terms of a specific trace + * + * @param trace the trace to which the annotation belongs + * @param annotation the annotation to be logged + * + * @returns 0 on success or negative error code + */ +int blkin_record(const struct blkin_trace *trace, + const struct blkin_annotation *annotation); + +/** + * Copy a blkin_trace_info struct into a the field info of a blkin_trace struct + * + * @param trace the destination + * @param info where to copy from + * + * @returns 0 on success or negative error code + */ +int blkin_get_trace_info(const struct blkin_trace *trace, + struct blkin_trace_info *info); + +/** + * Copy the blkin_trace_info from a blkin_trace to another blkin_trace_info + * + * @param trace the trace with the essential info + * @param info the destination + * + * @returns 0 on success or negative error code + */ +int blkin_set_trace_info(struct blkin_trace *trace, + const struct blkin_trace_info *info); + +/** + * Set the trace information, name and endpoint of a trace. + * + * @param trace the trace to which the properties will be assigned + * @param info blkin_trace_information with the trace identifiers + * @param name span name + * @param endpoint associated host + * + * @returns 0 on success or negative error code + */ +int blkin_set_trace_properties(struct blkin_trace *trace, + const struct blkin_trace_info *info, + const char *name, + const struct blkin_endpoint *endpoint); + +/** + * Convert a blkin_trace_info to the packed version. + * + * @param info The unpacked trace info. + * @param pinfo The provided packed version to be initialized. + * + * @returns 0 on success or negative error code + */ +int blkin_pack_trace_info(const struct blkin_trace_info *info, + struct blkin_trace_info_packed *pinfo); + +/** + * Convert a packed blkin_trace_info to the unpacked version. + * + * @param pinfo The provided packed version to be unpacked. + * @param info The unpacked trace info. + * + * @returns 0 on success or negative error code + */ +int blkin_unpack_trace_info(const struct blkin_trace_info_packed *pinfo, + struct blkin_trace_info *info); + +#endif /* ZIPKIN_C_H_ */ diff --git a/src/blkin/blkin-lib/zipkin_trace.h b/src/blkin/blkin-lib/zipkin_trace.h new file mode 100644 index 000000000..2a72d47bd --- /dev/null +++ b/src/blkin/blkin-lib/zipkin_trace.h @@ -0,0 +1,130 @@ +/* + * Zipkin lttng-ust tracepoint provider. + */ + +#undef TRACEPOINT_PROVIDER +#define TRACEPOINT_PROVIDER zipkin + +#undef TRACEPOINT_INCLUDE +#define TRACEPOINT_INCLUDE "./zipkin_trace.h" + +#if !defined(_ZIPKIN_H) || defined(TRACEPOINT_HEADER_MULTI_READ) +#define _ZIPKIN_H + +#include <lttng/tracepoint.h> + +TRACEPOINT_EVENT( + zipkin, + keyval_string, + TP_ARGS(const char *, trace_name, const char *, service, + int, port, const char *, ip, long, trace, + long, span, long, parent_span, + const char *, key, const char *, val ), + + TP_FIELDS( + /* + * Each span has a name mentioned on it in the UI + * This is the trace name + */ + ctf_string(trace_name, trace_name) + /* + * Each trace takes place in a specific machine-endpoint + * This is identified by a name, a port number and an ip + */ + ctf_string(service_name, service) + ctf_integer(int, port_no, port) + ctf_string(ip, ip) + /* + * According to the tracing semantics each trace should have + * a trace id, a span id and a parent span id + */ + ctf_integer(long, trace_id, trace) + ctf_integer(long, span_id, span) + ctf_integer(long, parent_span_id, parent_span) + /* + * The following is the real annotated information + */ + ctf_string(key, key) + ctf_string(val, val) + ) + ) +TRACEPOINT_LOGLEVEL( + zipkin, + keyval_string, + TRACE_WARNING) + +/* + * This tracepoint allows for integers to come out keyval + */ + +TRACEPOINT_EVENT( + zipkin, + keyval_integer, + TP_ARGS(const char *, trace_name, const char *, service, + int, port, const char *, ip, long, trace, + long, span, long, parent_span, + const char *, key, int64_t, val ), + + TP_FIELDS( + /* + * Each span has a name mentioned on it in the UI + * This is the trace name + */ + ctf_string(trace_name, trace_name) + /* + * Each trace takes place in a specific machine-endpoint + * This is identified by a name, a port number and an ip + */ + ctf_string(service_name, service) + ctf_integer(int, port_no, port) + ctf_string(ip, ip) + /* + * According to the tracing semantics each trace should have + * a trace id, a span id and a parent span id + */ + ctf_integer(long, trace_id, trace) + ctf_integer(long, span_id, span) + ctf_integer(long, parent_span_id, parent_span) + /* + * The following is the real annotated information + */ + ctf_string(key, key) + ctf_integer(int64_t, val, val) + ) + ) +TRACEPOINT_LOGLEVEL( + zipkin, + keyval_integer, + TRACE_WARNING) +/* + * In this event we follow the same semantics but we trace timestamp + * annotations + */ + +TRACEPOINT_EVENT( + zipkin, + timestamp, + TP_ARGS(const char *, trace_name, const char *, service, + int, port, const char *, ip, long, trace, + long, span, long, parent_span, + const char *, event), + + TP_FIELDS( + ctf_string(trace_name, trace_name) + ctf_string(service_name, service) + ctf_integer(int, port_no, port) + ctf_string(ip, ip) + ctf_integer(long, trace_id, trace) + ctf_integer(long, span_id, span) + ctf_integer(long, parent_span_id, parent_span) + ctf_string(event, event) + ) + ) +TRACEPOINT_LOGLEVEL( + zipkin, + timestamp, + TRACE_WARNING) +#endif /* _ZIPKIN_H */ + +#include <lttng/tracepoint-event.h> + diff --git a/src/blkin/blkin-lib/ztracer.hpp b/src/blkin/blkin-lib/ztracer.hpp new file mode 100644 index 000000000..3c4707ea4 --- /dev/null +++ b/src/blkin/blkin-lib/ztracer.hpp @@ -0,0 +1,248 @@ +/* + * Copyright 2014 Marios Kogias <marioskogias@gmail.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef ZTRACER_H + +#define ZTRACER_H + +#include <string> +extern "C" { +#include <zipkin_c.h> +} + +namespace ZTracer { + using std::string; + + const char* const CLIENT_SEND = "cs"; + const char* const CLIENT_RECV = "cr"; + const char* const SERVER_SEND = "ss"; + const char* const SERVER_RECV = "sr"; + const char* const WIRE_SEND = "ws"; + const char* const WIRE_RECV = "wr"; + const char* const CLIENT_SEND_FRAGMENT = "csf"; + const char* const CLIENT_RECV_FRAGMENT = "crf"; + const char* const SERVER_SEND_FRAGMENT = "ssf"; + const char* const SERVER_RECV_FRAGMENT = "srf"; + + static inline int ztrace_init() { return blkin_init(); } + + class Endpoint : private blkin_endpoint { + private: + string _ip; // storage for blkin_endpoint.ip, see copy_ip() + string _name; // storage for blkin_endpoint.name, see copy_name() + + friend class Trace; + public: + Endpoint(const char *name) + { + blkin_init_endpoint(this, "0.0.0.0", 0, name); + } + Endpoint(const char *ip, int port, const char *name) + { + blkin_init_endpoint(this, ip, port, name); + } + + // copy constructor and operator need to account for ip/name storage + Endpoint(const Endpoint &rhs) : _ip(rhs._ip), _name(rhs._name) + { + blkin_init_endpoint(this, _ip.size() ? _ip.c_str() : rhs.ip, + rhs.port, + _name.size() ? _name.c_str(): rhs.name); + } + const Endpoint& operator=(const Endpoint &rhs) + { + _ip.assign(rhs._ip); + _name.assign(rhs._name); + blkin_init_endpoint(this, _ip.size() ? _ip.c_str() : rhs.ip, + rhs.port, + _name.size() ? _name.c_str() : rhs.name); + return *this; + } + + // Endpoint assumes that ip and name will be string literals, and + // avoids making a copy and freeing on destruction. if you need to + // initialize Endpoint with a temporary string, copy_ip/copy_name() + // will store it in a std::string and assign from that + void copy_ip(const string &newip) + { + _ip.assign(newip); + ip = _ip.c_str(); + } + void copy_name(const string &newname) + { + _name.assign(newname); + name = _name.c_str(); + } + + void copy_address_from(const Endpoint *endpoint) + { + _ip.assign(endpoint->ip); + ip = _ip.c_str(); + port = endpoint->port; + } + void share_address_from(const Endpoint *endpoint) + { + ip = endpoint->ip; + port = endpoint->port; + } + void set_port(int p) { port = p; } + }; + + class Trace : private blkin_trace { + private: + string _name; // storage for blkin_trace.name, see copy_name() + + public: + // default constructor zero-initializes blkin_trace valid() + // will return false on a default-constructed Trace until + // init() + Trace() + { + // zero-initialize so valid() returns false + name = NULL; + info.trace_id = 0; + info.span_id = 0; + info.parent_span_id = 0; + endpoint = NULL; + } + + // construct a Trace with an optional parent + Trace(const char *name, const Endpoint *ep, const Trace *parent = NULL) + { + if (parent && parent->valid()) { + blkin_init_child(this, parent, ep ? : parent->endpoint, + name); + } else { + blkin_init_new_trace(this, name, ep); + } + } + + // construct a Trace from blkin_trace_info + Trace(const char *name, const Endpoint *ep, + const blkin_trace_info *i, bool child=false) + { + if (child) + blkin_init_child_info(this, i, ep, name); + else { + blkin_init_new_trace(this, name, ep); + set_info(i); + } + } + + // copy constructor and operator need to account for name storage + Trace(const Trace &rhs) : _name(rhs._name) + { + name = _name.size() ? _name.c_str() : rhs.name; + info = rhs.info; + endpoint = rhs.endpoint; + } + const Trace& operator=(const Trace &rhs) + { + _name.assign(rhs._name); + name = _name.size() ? _name.c_str() : rhs.name; + info = rhs.info; + endpoint = rhs.endpoint; + return *this; + } + + // return true if the Trace has been initialized + bool valid() const { return info.trace_id != 0; } + operator bool() const { return valid(); } + + // (re)initialize a Trace with an optional parent + int init(const char *name, const Endpoint *ep, + const Trace *parent = NULL) + { + if (parent && parent->valid()) + return blkin_init_child(this, parent, + ep ? : parent->endpoint, name); + + return blkin_init_new_trace(this, name, ep); + } + + // (re)initialize a Trace from blkin_trace_info + int init(const char *name, const Endpoint *ep, + const blkin_trace_info *i, bool child=false) + { + if (child) + return blkin_init_child_info(this, i, ep, _name.c_str()); + + return blkin_set_trace_properties(this, i, _name.c_str(), ep); + } + + // Trace assumes that name will be a string literal, and avoids + // making a copy and freeing on destruction. if you need to + // initialize Trace with a temporary string, copy_name() will store + // it in a std::string and assign from that + void copy_name(const string &newname) + { + _name.assign(newname); + name = _name.c_str(); + } + + const blkin_trace_info* get_info() const { return &info; } + void set_info(const blkin_trace_info *i) { info = *i; } + + // record key-value annotations + void keyval(const char *key, const char *val) const + { + if (valid()) + BLKIN_KEYVAL_STRING(this, endpoint, key, val); + } + void keyval(const char *key, int64_t val) const + { + if (valid()) + BLKIN_KEYVAL_INTEGER(this, endpoint, key, val); + } + void keyval(const char *key, const char *val, const Endpoint *ep) const + { + if (valid()) + BLKIN_KEYVAL_STRING(this, ep, key, val); + } + void keyval(const char *key, int64_t val, const Endpoint *ep) const + { + if (valid()) + BLKIN_KEYVAL_INTEGER(this, ep, key, val); + } + + // record timestamp annotations + void event(const char *event) const + { + if (valid()) + BLKIN_TIMESTAMP(this, endpoint, event); + } + void event(const char *event, const Endpoint *ep) const + { + if (valid()) + BLKIN_TIMESTAMP(this, ep, event); + } + }; + +} +#endif /* end of include guard: ZTRACER_H */ diff --git a/src/blkin/cmake/modules/FindLTTng.cmake b/src/blkin/cmake/modules/FindLTTng.cmake new file mode 100644 index 000000000..d0462a187 --- /dev/null +++ b/src/blkin/cmake/modules/FindLTTng.cmake @@ -0,0 +1,64 @@ +# - Find LTTng +# Find the Linux Trace Toolkit - next generation with associated includes path. +# See http://lttng.org/ +# +# This module accepts the following optional variables: +# LTTNG_PATH_HINT = A hint on LTTNG install path. +# +# This module defines the following variables: +# LTTNG_FOUND = Was LTTng found or not? +# LTTNG_EXECUTABLE = The path to lttng command +# LTTNG_LIBRARIES = The list of libraries to link to when using LTTng +# LTTNG_INCLUDE_DIR = The path to LTTng include directory +# +# On can set LTTNG_PATH_HINT before using find_package(LTTng) and the +# module with use the PATH as a hint to find LTTng. +# +# The hint can be given on the command line too: +# cmake -DLTTNG_PATH_HINT=/DATA/ERIC/LTTng /path/to/source + +find_package(PkgConfig) +pkg_check_modules(PC_LTTNG QUIET lttng-ust) + +find_path(LTTNG_INCLUDE_DIR + NAMES lttng/tracepoint.h + HINTS ${PC_LTTNG_INCLUDEDIR} ${PC_LTTNG_INCLUDE_DIRS} + PATH_SUFFIXES include + DOC "The LTTng include headers") + +find_path(LTTNG_LIBRARY_DIR + NAMES liblttng-ust.so + HINTS ${PC_LTTNG_LIBDIR} ${PC_LTTNG_LIBRARY_DIRS} + DOC "The LTTng libraries") + +find_library(LTTNG_UST_LIBRARY lttng-ust PATHS ${LTTNG_LIBRARY_DIR}) +find_library(URCU_LIBRARY urcu-bp PATHS ${LTTNG_LIBRARY_DIR}) +find_library(UUID_LIBRARY uuid) + +set(LTTNG_LIBRARIES ${LTTNG_UST_LIBRARY} ${URCU_LIBRARY} ${UUID_LIBRARY}) + +message(STATUS "Looking for lttng executable...") +set(LTTNG_NAMES "lttng;lttng-ctl") +# FIND_PROGRAM twice using NO_DEFAULT_PATH on first shot +find_program(LTTNG_EXECUTABLE + NAMES ${LTTNG_NAMES} + PATHS ${LTTNG_PATH_HINT}/bin + NO_DEFAULT_PATH + DOC "The LTTNG command line tool") +find_program(LTTNG_PROGRAM + NAMES ${LTTNG_NAMES} + PATHS ${LTTNG_PATH_HINT}/bin + DOC "The LTTNG command line tool") + +# handle the QUIETLY and REQUIRED arguments and set LTTNG_FOUND to TRUE if +# all listed variables are TRUE +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(LTTNG DEFAULT_MSG LTTNG_INCLUDE_DIR LTTNG_LIBRARY_DIR) +if (NOT LTTNG_FOUND) + if (LTTng_FIND_REQUIRED) + message(FATAL_ERROR "LTTng not found") + endif () +endif () + +mark_as_advanced(LTTNG_INCLUDE_DIR) +mark_as_advanced(LTTNG_LIBRARY_DIR) |