summaryrefslogtreecommitdiffstats
path: root/src/blkin
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:54:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:54:28 +0000
commite6918187568dbd01842d8d1d2c808ce16a894239 (patch)
tree64f88b554b444a49f656b6c656111a145cbbaa28 /src/blkin
parentInitial commit. (diff)
downloadceph-e6918187568dbd01842d8d1d2c808ce16a894239.tar.xz
ceph-e6918187568dbd01842d8d1d2c808ce16a894239.zip
Adding upstream version 18.2.2.upstream/18.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/blkin')
-rw-r--r--src/blkin/CMakeLists.txt9
-rw-r--r--src/blkin/COPYRIGHT27
-rw-r--r--src/blkin/README.md59
-rw-r--r--src/blkin/babeltrace-plugins/.gitignore2
-rw-r--r--src/blkin/babeltrace-plugins/json/README.md5
-rwxr-xr-xsrc/blkin/babeltrace-plugins/json/src/babeltrace_json.py88
-rw-r--r--src/blkin/babeltrace-plugins/scribe_client/__init__.py1
-rw-r--r--src/blkin/babeltrace-plugins/scribe_client/scribe_client.py31
-rw-r--r--src/blkin/babeltrace-plugins/zipkin/README.md6
-rwxr-xr-xsrc/blkin/babeltrace-plugins/zipkin/src/babeltrace_zipkin.py69
-rw-r--r--src/blkin/babeltrace-plugins/zipkin/src/zipkin_logic/__init__.py0
-rw-r--r--src/blkin/babeltrace-plugins/zipkin/src/zipkin_logic/formatters.py131
-rw-r--r--src/blkin/babeltrace-plugins/zipkin/src/zipkin_logic/trace.py137
-rw-r--r--src/blkin/babeltrace-plugins/zipkin/src/zipkin_logic/ttypes.py453
-rw-r--r--src/blkin/babeltrace-plugins/zipkin/src/zipkin_logic/zipkin_client.py70
-rw-r--r--src/blkin/babeltrace-plugins/zipkin/zipkin_trace.h67
-rw-r--r--src/blkin/blkin-lib/CMakeLists.txt18
-rw-r--r--src/blkin/blkin-lib/Makefile92
-rw-r--r--src/blkin/blkin-lib/tests/CMakeLists.txt15
-rw-r--r--src/blkin/blkin-lib/tests/Makefile55
-rw-r--r--src/blkin/blkin-lib/tests/test.c200
-rw-r--r--src/blkin/blkin-lib/tests/test.cc204
-rw-r--r--src/blkin/blkin-lib/tests/test_p.cc210
-rw-r--r--src/blkin/blkin-lib/tp.c35
-rw-r--r--src/blkin/blkin-lib/zipkin_c.c356
-rw-r--r--src/blkin/blkin-lib/zipkin_c.h334
-rw-r--r--src/blkin/blkin-lib/zipkin_trace.h130
-rw-r--r--src/blkin/blkin-lib/ztracer.hpp248
-rw-r--r--src/blkin/cmake/modules/FindLTTng.cmake64
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)