Code Monkey home page Code Monkey logo

tracing's Introduction

Tracing for Tarantool

tracing-img

Tracing module for Tarantool includes the following parts:

  • OpenTracing API
  • Zipkin tracer

Table of contents

OpenTracing

This library is a Tarantool platform API for OpenTracing.

Required Reading

To fully understand this platform API, it's helpful to be familiar with the OpenTracing project and terminology more specifically.

Conventions

  • All timestamps are in microseconds

Span

The β€œspan” is the primary building block of a distributed trace, representing an individual unit of work done in a distributed system. Traces in OpenTracing are defined implicitly by their Spans. In particular, a Trace can be thought of as a directed acyclic graph (DAG) of Spans, where the edges between Spans are called References.

local opentracing_span = require('opentracing.span')
-- tracer - External tracer
-- context - Span context
-- name - Name of span
-- start_timestamp (optional) - Time of span's start in microseconds (by default current time)
local span = opentracing_span.new(tracer, context, name, start_timestamp)

SpanContext

The SpanContext carries data across process boundaries.

local opentracing_span_context = require('opentracing.span_context')
-- trace_id (optional) - Trace ID (by default generates automatically)
-- span_id (optional) - Span ID (by default generates automatically)
-- parent_id (optional) - Span ID of parent span (by default is empty)
-- should_sample (optional) - Flag is enable collecting data of this span (by default false)
-- baggage (optional) - Table with trace baggage (by default is empty table)
local context = opentracing_span_context.new({
                    tracer_id = trace_id,
                    span_id = span_id,
                    parent_id = parent_id,
                    should_sample = should_sample,
                    baggage = baggage,
                })

Tracer

The Tracer interface creates Spans and understands how to Inject (serialize) and Extract (deserialize) their metadata across process boundaries.

An interface for custom tracers

local opentracing_tracer = require('opentracing.tracer')
-- reporter (optional) - Table with `report` method to process finished spans (by default no-op table)
-- sampler (optional) - Table with `sample` method to select traces to send to distributing tracing system (by default random selection)
-- But you can implement your own sampler with appropriate sampling strategy
-- For more information see: https://www.jaegertracing.io/docs/1.11/sampling/
local tracer = opentracing_tracer.new(reporter, sampler)

Basic usage

local zipkin = require('zipkin.tracer')
local opentracing = require('opentracing')

-- Create client to Zipkin and set it global for easy access from any part of app
local tracer = zipkin.new(config)
opentracing.set_global_tracer(tracer)

-- Create and manage spans manually
local span = opentracing.start_span('root span')
-- ... your code ...
span:finish()

-- Simple wrappers via user's function

-- Creates span before function call and finishes it after
local result = opentracing.trace('one span', func, ...)

-- Wrappers with context passing
local span = opentracing.start_span('root span')

-- Pass your function as third argument and then its arguments
opentracing.trace_with_context('child span 1', span:context(), func1, ...)
opentracing.trace_with_context('child span 2', span:context(), func2, ...)
span:finish()

Zipkin

Zipkin is a distributed tracing system.

It helps gather timing data needed to troubleshoot latency problems in microservice architectures. It manages both the collection and lookup of this data.

This module allows you to instance Zipkin Tracer that can start spans and will report collected spans to Zipkin Server.

Basic usage

local zipkin = require('zipkin.tracer')
-- First argument is config that contains url of Zipkin API,
--  method to send collected traces and interval of reports in seconds
-- Second optional argument is Sampler (see OpenTracing API description), by default random sampler
local tracer = zipkin.new({
    base_url = 'localhost:9411/api/v2/spans',
    api_method = 'POST',
    report_interval = 0,
}, Sampler)

local span = tracer:start_span('example')
-- ...
span:finish()

Examples

HTTP

http-example-img

This example is a Lua port of Go OpenTracing tutorial.

Complete source code see here

Description

The example demonstrates trace propagation through two services: formatter that formats the source string to "Hello, world" and publisher that prints it in the console.

Add data to these services via HTTP; initially it sends client.

Note: example requires http rock (version >= 1.2.0) Install it using tt rocks install http 1.2.0

How to run

  • Create docker-compose.zipkin.yml
---
version: '3.5'

# Initially got from https://github.com/openzipkin/docker-zipkin/blob/master/docker-compose.yml

services:
  storage:
    image: openzipkin/zipkin-mysql:1
    container_name: mysql
    networks:
      - zipkin
    ports:
      - 3306:3306

  # The zipkin process services the UI, and also exposes a POST endpoint that
  # instrumentation can send trace data to. Scribe is disabled by default.
  zipkin:
    image: openzipkin/zipkin:1
    container_name: zipkin
    networks:
      - zipkin
    # Environment settings are defined here https://github.com/openzipkin/zipkin/tree/1.19.0/zipkin-server#environment-variables
    environment:
      - STORAGE_TYPE=mysql
      # Point the zipkin at the storage backend
      - MYSQL_HOST=mysql
      # Enable debug logging
      - JAVA_OPTS=-Dlogging.level.zipkin=DEBUG -Dlogging.level.zipkin2=DEBUG
    ports:
      # Port used for the Zipkin UI and HTTP Api
      - 9411:9411
    depends_on:
      - storage

  # Adds a cron to process spans since midnight every hour, and all spans each day
  # This data is served by http://192.168.99.100:8080/dependency
  #
  # For more details, see https://github.com/openzipkin/docker-zipkin-dependencies
  dependencies:
    image: openzipkin/zipkin-dependencies:1
    container_name: dependencies
    entrypoint: crond -f
    networks:
      - zipkin
    environment:
      - STORAGE_TYPE=mysql
      - MYSQL_HOST=mysql
      # Add the baked-in username and password for the zipkin-mysql image
      - MYSQL_USER=zipkin
      - MYSQL_PASS=zipkin
      # Dependency processing logs
      - ZIPKIN_LOG_LEVEL=DEBUG
    depends_on:
      - storage

networks:
  zipkin:
  • Start Zipkin docker-compose -f docker-compose.zipkin.yml up

  • Run mock applications from separate consoles: consumer, formatter and client

Formatter HTTP server

#!/usr/bin/env tarantool

local http_server = require('http.server')
local fiber = require('fiber')
local log = require('log')
local zipkin = require('zipkin.tracer')
local opentracing = require('opentracing')

local app = {}

local Sampler = {
    sample = function() return true end,
}

local HOST = '0.0.0.0'
local PORT = '33302'

local function handler(req)
    -- Extract content from request's http headers
    local ctx, err = opentracing.http_extract(req.headers)
    if ctx == nil then
        local resp = req:render({ text = err })
        resp.status = 400
        return resp
    end

    local hello_to = req:query_param('helloto')
    -- Start new child span
    local span = opentracing.start_span_from_context(ctx, 'format_string')
    -- Set service type
    span:set_component('formatter')
    span:set_server_kind()
    span:set_http_method(req.method)
    span:set_http_path(req.path)
    local greeting = span:get_baggage_item('greeting')
    local result = ('%s, %s!'):format(greeting, hello_to)
    local resp = req:render({ text = result })

    -- Simulate long request processing
    fiber.sleep(2)
    span:log_kv({
        event = 'String format',
        value = result,
    })
    resp.status = 200
    span:set_http_status_code(resp.status)
    span:finish()
    return resp
end

function app.init()
    -- Initialize zipkin client that will be send spans every 5 seconds
    local tracer = zipkin.new({
        base_url = 'localhost:9411/api/v2/spans',
        api_method = 'POST',
        report_interval = 5,
        on_error = function(err) log.error(err) end,
    }, Sampler)
    opentracing.set_global_tracer(tracer)

    local httpd = http_server.new(HOST, PORT)
    httpd:route({ path = '/format', method = 'GET' }, handler)
    httpd:start()
end

app.init()

return app

Publisher HTTP server

#!/usr/bin/env tarantool

local http_server = require('http.server')
local fiber = require('fiber')
local log = require('log')
local zipkin = require('zipkin.tracer')
local opentracing = require('opentracing')

local app = {}

local Sampler = {
    sample = function() return true end,
}

local HOST = '0.0.0.0'
local PORT = '33303'

local function handler(req)
    local ctx, err = opentracing.http_extract(req.headers)

    if ctx == nil then
        local resp = req:render({ text = err })
        resp.status = 400
        return resp
    end

    local hello = req:query_param('hello')
    local span = opentracing.start_span_from_context(ctx, 'print_string')
    span:set_component('publisher')
    span:set_server_kind()
    span:set_http_method(req.method)
    span:set_http_path(req.path)

    -- Simulate long request processing
    fiber.sleep(3)

    io.write(hello, '\n')
    local resp = req:render({text = '' })
    resp.status = 200
    span:set_http_status_code(resp.status)
    span:finish()
    return resp
end

function app.init()
    local tracer = zipkin.new({
        base_url = 'localhost:9411/api/v2/spans',
        api_method = 'POST',
        report_interval = 5,
        on_error = function(err) log.error(err) end,
    }, Sampler)
    opentracing.set_global_tracer(tracer)

    local httpd = http_server.new(HOST, PORT)
    httpd:route({ path = '/print', method = 'GET' }, handler)
    httpd:start()
end

app.init()

return app

Client

#!/usr/bin/env tarantool

local http_client = require('http.client')
local json = require('json')
local log = require('log')
local fiber = require('fiber')
local zipkin = require('zipkin.tracer')
local opentracing = require('opentracing')

local app = {}

-- Process all requests
local Sampler = {
    sample = function() return true end,
}

local function url_encode(str)
    local res = string.gsub(str, '[^a-zA-Z0-9_]',
        function(c)
            return string.format('%%%02X', string.byte(c))
        end
    )
    return res
end

-- Client part to formatter
local formatter_url = 'http://localhost:33302/format'
local function format_string(ctx, str)
    local span = opentracing.start_span_from_context(ctx, 'format_string')
    local httpc = http_client.new()
    span:set_component('client')
    span:set_client_kind()
    span:set_http_method('GET')
    span:set_http_url(formatter_url)

    -- Use http headers as carrier
    local headers = {
        ['content-type'] = 'application/json'
    }
    opentracing.http_inject(span:context(), headers)

    -- Simulate problems with network
    fiber.sleep(1)
    local resp = httpc:get(formatter_url .. '?helloto=' .. url_encode(str),
            { headers = headers })
    fiber.sleep(1)

    span:set_http_status_code(resp.status)
    if resp.status ~= 200 then
        error('Format string error: ' .. json.encode(resp))
    end
    local result = resp.body
    -- Log result
    span:log_kv({
        event = 'String format',
        value = result
    })
    span:finish()
    return result
end

-- Client part to publisher
local printer_url = 'http://localhost:33303/print'
local function print_string(ctx, str)
    local span = opentracing.start_span_from_context(ctx, 'print_string')
    local httpc = http_client.new()
    span:set_component('client')
    span:set_client_kind()
    span:set_http_method('GET')
    span:set_http_url(printer_url)

    local headers = {
        ['content-type'] = 'application/json'
    }
    opentracing.http_inject(span:context(), headers)

    -- Simulate problems with network
    fiber.sleep(1)
    local resp = httpc:get(printer_url .. '?hello=' .. url_encode(str),
            { headers = headers })
    fiber.sleep(1)

    span:set_http_status_code(resp.status)
    if resp.status ~= 200 then
        error('Print string error: ' .. json.encode(resp))
    end
    span:finish()
end

function app.init()
    -- Initialize Zipkin tracer
    local tracer = zipkin.new({
        base_url = 'localhost:9411/api/v2/spans',
        api_method = 'POST',
        report_interval = 0,
        on_error = function(err) log.error(err) end,
    }, Sampler)
    opentracing.set_global_tracer(tracer)

    -- Initialize root span
    local span = opentracing.start_span('Hello-world')

    local hello_to = 'world'
    local greeting = 'my greeting'
    span:set_component('client')
    -- Set service type
    span:set_client_kind()
    -- Set tag with metadata
    span:set_tag('hello-to', hello_to)
    -- Add data to baggage
    span:set_baggage_item('greeting', greeting)

    local ctx = span:context()
    local formatted_string = format_string(ctx, hello_to)
    print_string(ctx, formatted_string)
    span:finish()
end

app.init()

os.exit(0)

Tarantool Cartridge

cartridge-example-img

Complete source code see here

Opentracing could be used with Tarantool Cartridge.

This example is pretty similar to previous. We will have several roles that communicate via rpc_call.

Basics

Before describing let's define some restrictions of "tracing in Tarantool". Remote communications between tarantools are made using net.box module. It allows to send only primitive types (except functions) and doesn't have containers for request context (as headers in HTTP). Then you should transfer span context explicitly as raw table as additional argument in your function.

-- Create span
local span = opentracing.start_span('span')

-- Create context carrier
local rpc_context = {}
opentracing.map_inject(span:context(), rpc_context)

-- Pass context explicitly as additional argument
local res, err = cartridge.rpc_call('role', 'fun', {rpc_context, ...})

Using inside roles

The logic of tracing fits into a separate permanent role. Let's define it:

local opentracing = require('opentracing')
local zipkin = require('zipkin.tracer')

local log = require('log')

-- config = {
--     base_url = 'localhost:9411/api/v2/spans',
--     api_method = 'POST',
--     report_interval = 5,    -- in seconds
--     spans_limit = 1e4,      -- amount of spans that could be stored locally
-- }

local function apply_config(config)
    -- sample all requests
    local sampler = { sample = function() return true end }

    local tracer = zipkin.new({
        base_url = config.base_url,
        api_method = config.api_method,
        report_interval = config.report_interval,
        spans_limit = config.spans_limit,
        on_error = function(err) log.error('zipkin error: %s', err) end,
    }, sampler)

    -- Setup global tracer for easy access from another modules
    opentracing.set_global_tracer(tracer)

    return true
end

return {
    role_name = 'tracing',
    apply_config = apply_config,
    dependencies = {},
    -- Role will be hidden from WebUI
    -- but constantly enabled on all instances,
    -- no need to specify it as dependency for other roles
    permanent = true,
}

Then you can use this role as dependency:

local opentracing = require('opentracing')
local membership = require('membership')

local role_name = 'formatter'
local template = 'Hello, %s'

local service_uri = ('%s@%s'):format(role_name, membership.myself().uri)

local function format(ctx, input)
    -- Extract tracing context from request context
    local context = opentracing.map_extract(ctx)
    local span = opentracing.start_span_from_context(context, 'format')
    span:set_component(service_uri)

    local result, err
    if input == '' then
        err = 'Empty string'
        span:set_error(err)
    else
        result = template:format(input)
    end

    span:finish()

    return result, err
end

local function init(_)
    return true
end

local function stop()
end

local function validate_config(_, _)
    return true
end

local function apply_config(_, _)
    return true
end

return {
    format = format,

    role_name = role_name,
    init = init,
    stop = stop,
    validate_config = validate_config,
    apply_config = apply_config,
    dependencies = {},
}

tracing's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

tracing's Issues

how to install tarantool ?

intall tarantool in this way https://www.tarantool.io/en/download/os-installation/1.10/rhel-centos-6-7/ . but run tarantoolctl rocks install http 2.0.1 error, like this :

Installing http://rocks.tarantool.org/http-2.0.1-1.rockspec

Error: Could not find header file for TARANTOOL
No file tarantool/module.h in /usr/local/include
No file tarantool/module.h in /usr/include
You may have to install TARANTOOL in your system and/or pass TARANTOOL_DIR or TARANTOOL_INCDIR to the luarocks command.
Example: luarocks install http TARANTOOL_DIR=/usr/local

example client fails

Prerequirements:
tarantoolctl rocks install http 2.0.1
tarantoolctl rocks install tracing

Run:
tarantool formatter.lua,
tarantool publisher.lua in separate terminal window,
tarantool client.lua in separate terminal window.

Last one fails with

LuajitError: client.lua:85: Print string error: {"status":595,"reason":"Couldn't connect to server"}
fatal error, exiting the event loop

while tarantool formatter.lua still logs

started
entering the event loop
GET /format?helloto=world

tarantool publisher.lua logs only

entering the event loop

and there are some traces in Jagger:
image

zipkin docker start error

docker-compose -f docker-compose.zipkin.yml up fails both for me and @ZolotarevIgor-mail-ru with

zipkin          | java.sql.SQLInvalidAuthorizationSpecException: Could not connect to address=(host=mysql)(port=3306)(type=master) : (conn=662) Access denied for user 'zipkin'@'zipkin.tracing_zipkin' (using password: NO)
zipkin          | 	at org.mariadb.jdbc.internal.util.exceptions.ExceptionFactory.createException(ExceptionFactory.java:66) ~[mariadb-java-client-2.7.1.jar:?]
zipkin          | 	at org.mariadb.jdbc.internal.util.exceptions.ExceptionFactory.create(ExceptionFactory.java:192) ~[mariadb-java-client-2.7.1.jar:?]
zipkin          | 	at org.mariadb.jdbc.internal.protocol.AbstractConnectProtocol.connectWithoutProxy(AbstractConnectProtocol.java:1392) ~[mariadb-java-client-2.7.1.jar:?]
zipkin          | 	at org.mariadb.jdbc.internal.util.Utils.retrieveProxy(Utils.java:635) ~[mariadb-java-client-2.7.1.jar:?]
zipkin          | 	at org.mariadb.jdbc.MariaDbConnection.newConnection(MariaDbConnection.java:150) ~[mariadb-java-client-2.7.1.jar:?]
zipkin          | 	at org.mariadb.jdbc.Driver.connect(Driver.java:89) ~[mariadb-java-client-2.7.1.jar:?]
zipkin          | 	at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:121) ~[HikariCP-3.4.5.jar:?]
zipkin          | 	at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:358) ~[HikariCP-3.4.5.jar:?]
zipkin          | 	at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:206) ~[HikariCP-3.4.5.jar:?]
zipkin          | 	at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:477) ~[HikariCP-3.4.5.jar:?]
zipkin          | 	at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:560) ~[HikariCP-3.4.5.jar:?]
zipkin          | 	at com.zaxxer.hikari.pool.HikariPool.<init>(HikariPool.java:115) ~[HikariCP-3.4.5.jar:?]
zipkin          | 	at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:112) ~[HikariCP-3.4.5.jar:?]
zipkin          | 	at zipkin2.storage.mysql.v1.MySQLStorage.check(MySQLStorage.java:159) ~[zipkin-storage-mysql-v1-2.23.2.jar:?]
zipkin          | 	at zipkin2.server.internal.health.ComponentHealth.ofComponent(ComponentHealth.java:27) ~[classes/:?]
zipkin          | 	at zipkin2.server.internal.health.ZipkinHealthController.lambda$health$1(ZipkinHealthController.java:69) ~[classes/:?]
zipkin          | 	at java.util.concurrent.CompletableFuture$AsyncSupply.run(Unknown Source) ~[?:?]
zipkin          | 	at com.linecorp.armeria.common.RequestContext.lambda$makeContextAware$3(RequestContext.java:502) ~[armeria-1.3.0.jar:?]
zipkin          | 	at io.micrometer.core.instrument.internal.TimedRunnable.run(TimedRunnable.java:44) [micrometer-core-1.6.2.jar:1.6.2]
zipkin          | 	at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source) [?:?]
zipkin          | 	at java.util.concurrent.FutureTask.run(Unknown Source) [?:?]
zipkin          | 	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source) [?:?]
zipkin          | 	at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) [?:?]
zipkin          | 	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [?:?]
zipkin          | 	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) [netty-common-4.1.54.Final.jar:4.1.54.Final]
zipkin          | 	at java.lang.Thread.run(Unknown Source) [?:?]
zipkin          | Caused by: java.sql.SQLInvalidAuthorizationSpecException: (conn=662) Access denied for user 'zipkin'@'zipkin.tracing_zipkin' (using password: NO)
zipkin          | 	at org.mariadb.jdbc.internal.util.exceptions.ExceptionFactory.createException(ExceptionFactory.java:66) ~[mariadb-java-client-2.7.1.jar:?]
zipkin          | 	at org.mariadb.jdbc.internal.util.exceptions.ExceptionFactory.create(ExceptionFactory.java:187) ~[mariadb-java-client-2.7.1.jar:?]
zipkin          | 	at org.mariadb.jdbc.internal.protocol.AbstractConnectProtocol.authenticationHandler(AbstractConnectProtocol.java:776) ~[mariadb-java-client-2.7.1.jar:?]
zipkin          | 	at org.mariadb.jdbc.internal.protocol.AbstractConnectProtocol.createConnection(AbstractConnectProtocol.java:553) ~[mariadb-java-client-2.7.1.jar:?]
zipkin          | 	at org.mariadb.jdbc.internal.protocol.AbstractConnectProtocol.connectWithoutProxy(AbstractConnectProtocol.java:1387) ~[mariadb-java-client-2.7.1.jar:?]
zipkin          | 	... 23 more

Example uses deprecated HTTP v2

tracing/README.md

Lines 241 to 313 in 9feeae6

```lua
#!/usr/bin/env tarantool
local http_server = require('http.server')
local http_router = require('http.router')
local fiber = require('fiber')
local log = require('log')
local zipkin = require('zipkin.tracer')
local opentracing = require('opentracing')
local app = {}
local Sampler = {
sample = function() return true end,
}
local HOST = '0.0.0.0'
local PORT = '33302'
local function handler(req)
-- Extract content from request's http headers
local ctx, err = opentracing.http_extract(req:headers())
if ctx == nil then
local resp = req:render({ text = err })
resp.status = 400
return resp
end
local hello_to = req:query_param('helloto')
-- Start new child span
local span = opentracing.start_span_from_context(ctx, 'format_string')
-- Set service type
span:set_component('formatter')
span:set_server_kind()
span:set_http_method(req:method())
span:set_http_path(req:path())
local greeting = span:get_baggage_item('greeting')
local result = ('%s, %s!'):format(greeting, hello_to)
local resp = req:render({ text = result })
-- Simulate long request processing
fiber.sleep(2)
span:log_kv({
event = 'String format',
value = result,
})
resp.status = 200
span:set_http_status_code(resp.status)
span:finish()
return resp
end
function app.init()
-- Initialize zipkin client that will be send spans every 5 seconds
local tracer = zipkin.new({
base_url = 'localhost:9411/api/v2/spans',
api_method = 'POST',
report_interval = 5,
on_error = function(err) log.error(err) end,
}, Sampler)
opentracing.set_global_tracer(tracer)
local httpd = http_server.new(HOST, PORT)
local router = http_router.new()
:route({ path = '/format', method = 'GET' }, handler)
httpd:set_router(router)
httpd:start()
end
app.init()
return app
```
and

tracing/README.md

Lines 317 to 382 in 9feeae6

#!/usr/bin/env tarantool
local http_server = require('http.server')
local http_router = require('http.router')
local fiber = require('fiber')
local log = require('log')
local zipkin = require('zipkin.tracer')
local opentracing = require('opentracing')
local app = {}
local Sampler = {
sample = function() return true end,
}
local HOST = '0.0.0.0'
local PORT = '33303'
local function handler(req)
local ctx, err = opentracing.http_extract(req:headers())
if ctx == nil then
local resp = req:render({ text = err })
resp.status = 400
return resp
end
local hello = req:query_param('hello')
local span = opentracing.start_span_from_context(ctx, 'print_string')
span:set_component('publisher')
span:set_server_kind()
span:set_http_method(req:method())
span:set_http_path(req:path())
-- Simulate long request processing
fiber.sleep(3)
io.write(hello, '\n')
local resp = req:render({text = '' })
resp.status = 200
span:set_http_status_code(resp.status)
span:finish()
return resp
end
function app.init()
local tracer = zipkin.new({
base_url = 'localhost:9411/api/v2/spans',
api_method = 'POST',
report_interval = 5,
on_error = function(err) log.error(err) end,
}, Sampler)
opentracing.set_global_tracer(tracer)
local httpd = http_server.new(HOST, PORT)
local router = http_router.new()
:route({ path = '/print', method = 'GET' }, handler)
httpd:set_router(router)
httpd:start()
end
app.init()
return app
```
use HTTP v2 module, which is deprecated now (tarantool/http#142). HTTP v1 is installed by default from servers and, since v1 and v2 code is incompatible, example fails. It confuses users trying to run code from README (https://t.me/tarantoolru/182158).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.