New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Client libraries in different languages #366

Open
yurishkuro opened this Issue Sep 1, 2017 · 40 comments

Comments

Projects
None yet
9 participants
@yurishkuro
Member

yurishkuro commented Sep 1, 2017

This issue tracks various implementations of tracing clients in different languages, either already available or under development.

As a guideline, the following is a rough outline for getting a new client out:

  1. setup new project, travis build, code coverage, release publishing, etc.
  2. implement basic tracer & span functionality with a simple 100% sampling & a configuration mechanism
  3. implement remote reporter with abstract sender
  4. implement UDP or HTTP sender or both
  5. implement crossdock integration tests
  6. implement other samplers (probabilistic, rate limiting)
  7. implement remote sampler that pulls sampling strategy from the agent
  8. implement adaptive sampler
  9. optionally other features like baggage whitelisting

Steps 1-4 are needed to get a minimal viable client. Steps 5-9 could be added later.

@gideonkorir

This comment has been minimized.

gideonkorir commented Sep 9, 2017

Hi, trying to add a C# client porting from the Java client but still very early; I just started today.

Any feedback would be helpful

@rbtcollins

This comment has been minimized.

Contributor

rbtcollins commented Oct 16, 2017

I note that neither Rust nor lua are on your list? Any plans to add them? (We are using openresty which leads to the Lua interest, and Rust - well Rust is cool :))

@yurishkuro

This comment has been minimized.

Member

yurishkuro commented Oct 16, 2017

If someone implements then then we'd be glad to include in the official list. So far I haven't seen anyone asking/trying, so no plans.

Also, we're working on a c++ client, I wonder if some of the languages can be done as wrappers on top of that.

@rbtcollins

This comment has been minimized.

Contributor

rbtcollins commented Oct 16, 2017

I'd very much encourage writing such a low level client in a more modern systems language like Rust : more cleanly bindable to C (no need to explicitly opt out of the rtti support or pull in the C++ support libraries), and very very safe.

We have some components that are nginx+openresty, so we have interest in Lua (language) support + openresty bindings : I am thinking we'll just implement the whole store in Lua rather than have to surface span data from a C++ module back up through nginx's C core and then in to Lua.

@mfilotto

This comment has been minimized.

mfilotto commented Oct 20, 2017

Anything yet for Javascript in browser ?

@yurishkuro

This comment has been minimized.

Member

yurishkuro commented Oct 20, 2017

Nobody is working on it right now (jaegertracing/jaeger-client-javascript#1 - help wanted)

@isaachier

This comment has been minimized.

Contributor

isaachier commented Oct 30, 2017

@rbtcollins I wonder what the performance will look like compared to just wrapping the C++ client in a luarocks package and using that.

@yurishkuro I have also been wondering what it would take to wrap all the client languages around the C++ client. Here is the plan as of now:

Java: JNI (no one likes it though, so IDK)
Go: cgo
Python: C module
Node.js: C++ add-on
JavaScript: Emscripten
Ruby: C++ extension
PHP: C module
Lua: C++ bindings

The easiest, by far, is Lua (I have some experience here). The others might be harder. On the flip-side, I wonder how easy it is to do this very same thing with the Go client once it is compiled. Any thoughts and/or experience here would be greatly appreciated.

@yurishkuro

This comment has been minimized.

Member

yurishkuro commented Oct 30, 2017

Yes, we discussed the possibility, but until we actually try with some languages it's hard to see all pros & cons (and there are a lot of cons to wrapping).

@rbtcollins

This comment has been minimized.

Contributor

rbtcollins commented Oct 31, 2017

@isaachier I have zero interest in debugging interactions between C++ RTTI and exceptions, and any host language. We need anything that is going to be surfaced in such a way to be rock solid and have no corner cases that will make it a liability rather than an asset.

rustlang or C would make good 'lowest common denominator' languages, if having a bridge mechanism to a single set of implementation backends is desirable - they can both be bound to with no runtime support, without having to disable language features (unlike e.g. C++ where the default requires runtime support).

That said, I fully expect every non-trivial language to demand, and get, 100% native bindings. There's nothing in Opentracing/Jaeger/Thrift that would make native support hard/infeasible.

On the list of languages you've got, I can specifically say:

  • that we could tolerate JNI, but would very much prefer to avoid it because of the overheads involved in something in our core request path.
  • Python - C modules make deployment harder, so would stay with the current implementation.
  • Javascript - emscripten is awesome and clever and huge. Not even going to consider it. We'd probably use the zipkin endpoint so that we can have a super minimal implementation with no Thrift involved at all.
  • Lua in the context of openresty: Would very much prefer not to have to install additional modules into nginx over what the stock docker images contain, so yeah - again, native is super appealing.
@isaachier

This comment has been minimized.

Contributor

isaachier commented Nov 1, 2017

@rbtcollins interesting point about Rust vs. C++. I am actually amazed to hear that you prefer Rust to C++ in the area of language bindings. I had always heard the compiler support for Rust is much more limited than C++, and neither compare to C, which has a compiler for almost every conceivable platform. But I do understand the concern. For that reason, I think gRPC was motivated to write its core library in C++ without any STL (making it pretty much C).

Meanwhile, I think you are correct that the "best" thing would be to have a native library for each and every language. But I'm interested in hearing your opinion for the following difficulties:

  • Some languages just do not have good multithreading support (i.e. Python). A C module would perform much better than anything in the native language.
  • How do we implement changes consistently once the number of languages goes up? As of now, our Python client still uses the older Zipkin format instead of our better Jaeger format. The main reason is the cost associated with maintaining multiple client libraries.
  • Although C modules/packages are more difficult to deal with than their native language counterparts, almost every major package manager has a good way of dealing with this, be it pip, luarocks, or gem. How difficult is it using these tools?
  • Individual, language-specific libraries are by definition less tested. By uniting all of the languages with a common core library, we can guarantee the core itself is bug-free.
@yurishkuro

This comment has been minimized.

Member

yurishkuro commented Nov 1, 2017

I am also interested in another consideration - if we take our Python client and reimplement it as a wrapper on top of C++ client, how much functionality will be removed from the pure-Python part of the combo? We still have to implement the OpenTracing API, but probably concerns like different samplers, retrieving samplers from the agent, and the whole async span reporting could be moved to C part.

Although C modules/packages are more difficult to deal with than their native language counterparts, almost every major package manager has a good way of dealing with this, be it pip, luarocks, or gem.

I tend to agree with that, not so much based on experience, but on the fact that out Python/Node clients already depend on modules like thriftrw which use C bindings and require compilation during install. But we only use Linux/MacOS, so don't know how well this would work on other platforms.

@isaachier

This comment has been minimized.

Contributor

isaachier commented Nov 1, 2017

About the bindings, there is a certain amount of bridge code for each language. I think it comes down to how much you want the code to look idiomatic (i.e. avoiding calling Python functions with mysterious handle objects, manual resource management, and the like). I'd advocate not using the language itself to implement span objects etc. because of the repetition and the memory overhead. This takes some clever coding but isn't too hard.

The build shouldn't really be a concern. The only thing I worry about is the C vs. C++ debate. Worst case scenario, we could refactor some of the core C++ types to C structs. The only reason I haven't yet considered that seriously is that there is no OpenTracing C API, and if that API is released down the line, it would probably invalidate any Jaeger-specific code I write now.

@yurishkuro

This comment has been minimized.

Member

yurishkuro commented Nov 1, 2017

I'd advocate not using the language itself to implement span objects etc. because of the repetition and the memory overhead. This takes some clever coding but isn't too hard.

I don't see how you'd do that since the end user is still going to interact with object-oriented OpenTracing API. Unless you're saying that you can create C-bound objects that look like normal host language objects to the end user.

@isaachier

This comment has been minimized.

Contributor

isaachier commented Nov 1, 2017

Ya essentially all fields are in the C struct and you point all setters and getters to conversion functions so they get a pretty Python/Ruby/Lua value. If you want to be really efficient you can do this at multiple levels so there is truly no-copying/allocation beyond that initial struct. For example, consider using a custom tag list struct instead of copying tags into a new Python list. Then implement Python list operations for the tag list struct. The client doesn't realize it isn't a native list because it implements the sequence interface.

@rbtcollins

This comment has been minimized.

Contributor

rbtcollins commented Nov 1, 2017

@isaachier by compiler support for rust, I'm not sure what you're referring to. Rust was built to integrate with Firefox's core - thats a primary use case for it (and it has delivered many of the major perf improvements in recent firefox :)).

What memory overhead are you worried about with native implementations? Remember that when you have bindings you end up with separate arenas for the external objects, which can spread memory footprint out somewhat.

@isaachier

This comment has been minimized.

Contributor

isaachier commented Nov 1, 2017

I mean embedded systems. I know there is interest in tracing for IoT devices. Rust may not target these devices as well as C++. Memory isn't the main consideration here. More of a bonus.

@rbtcollins

This comment has been minimized.

Contributor

rbtcollins commented Nov 2, 2017

@isaachier

This comment has been minimized.

Contributor

isaachier commented Nov 2, 2017

OK did some research and cannot find much evidence that C is inherently better for bindings than C++ with and C wrapper API (i.e. extern "C"). Please let me know if you have a good source I can read on this issue.

@lvht

This comment has been minimized.

lvht commented Dec 2, 2017

Hi @yurishkuro , would you like to accept the lvht/jaeger-php as the official PHP client of Jaeger?

@yurishkuro

This comment has been minimized.

Member

yurishkuro commented Dec 2, 2017

@lvht let's discuss on #211

@autodidaddict

This comment has been minimized.

autodidaddict commented Dec 7, 2017

Have not tried this, but here is a Rust Jaeger client built on top of another Rust opentracing API: rustracing_jaeger

@isaachier

This comment has been minimized.

Contributor

isaachier commented Mar 12, 2018

BTW @rbtcollins Rust just announced they will be working on better embedded support this year. https://internals.rust-lang.org/t/announcing-the-embedded-devices-working-group/6839

@ldeveloperl1985

This comment has been minimized.

ldeveloperl1985 commented Jun 28, 2018

is there any Lua client or any other way to use jaeger in Lua language?

@isaachier

This comment has been minimized.

Contributor

isaachier commented Jun 28, 2018

@ldeveloperl1985 that largely depends on whether or not OpenTracing decides to support Lua. Also, the issue of many different dialects makes the situation much more difficult. Which version of Lua do you use? Is it original Lua or LuaJIT?

@ldeveloperl1985

This comment has been minimized.

ldeveloperl1985 commented Jun 28, 2018

I've used kong 0.11v. which uses Lua 5.1 and LuaJIT 2.1.0

@isaachier

This comment has been minimized.

Contributor

isaachier commented Jun 28, 2018

Kong is probably the primary use case. I am not familiar with that version, but does it support 64 bit integers? My problem is maintaining compatibility across several versions of Lua.

@ldeveloperl1985

This comment has been minimized.

ldeveloperl1985 commented Jun 29, 2018

You can easily maintain compatibility across several versions of LUA. Lua is a dynamically typed language. There are no type definitions in the language; each value carries its own type.

@isaachier

This comment has been minimized.

Contributor

isaachier commented Jun 29, 2018

That is much easier said than done. I know for a fact that 64 bit integers are only supported in >= 5.3. Also, I believe the C API has inconsistencies across minor versions and LuaJIT.

@yurishkuro

This comment has been minimized.

Member

yurishkuro commented Jun 29, 2018

@ldeveloperl1985 @isaachier let's move Lua discussion to #898

@jalberto

This comment has been minimized.

jalberto commented Jul 17, 2018

I suggest to add Elixir to the list :)

@isaachier

This comment has been minimized.

Contributor

isaachier commented Jul 17, 2018

@jalberto I'm really hoping to move away from more client maintenance. We can probably use C to glue together an Elixir/Erlang client.

@jalberto

This comment has been minimized.

jalberto commented Jul 17, 2018

@isaachier so maybe every client (backend) should be a wrapper to C client to have features parity. If some clientes are native, adn others are just wrappers, there is a risk to split features set.

@isaachier

This comment has been minimized.

Contributor

isaachier commented Jul 17, 2018

There is already significant feature split among the clients. And if I thought anyone would want to use C other than myself, I'd agree with you about using the same C library for all clients. However, some languages make this approach easier than others. For example, I have heard Java's JIT makes calling a native function significantly slower than calling the equivalent Java code.

@jalberto

This comment has been minimized.

jalberto commented Jul 17, 2018

well, using a wrapper/binding to a different lang will always create an impact, in particular in this kind of libs that need to be called very often.

In other hand to use a C-binding-wrapper may cause some headache dependencies-side or deployment-side even with docker (imagemagick in ruby or perl is a good example). Also docker images using alpine or any version of non-glibc can be tricky at least.

IMHO as there is not perfect solution I suggest to avoid hybrid solutions (that will increase troubles surface), I suggest to go one side or the other:

  • use a C lib/sys-cmd+wrapper for every backend client
  • or create a client per language
  • or support opentracing clients

To have some langs with native clients and other with a wrapper can icnrease th eamount of work instead of reducing it, also it may:

  • 1st class vs 2nd class clients (updates, new features, etc)
  • features disparity
  • outdated clients
  • etc
@isaachier

This comment has been minimized.

Contributor

isaachier commented Jul 17, 2018

I'll agree that the C based clients are going to be second class, mostly because they aren't languages we ever use. The notable exception here is C# where an external contributor volunteered to maintain it. Among the Jaeger developers at Uber, I don't believe C# is our top priority.

Regarding packaging, people complain about it, but whether you like it or not many libraries rely on C bindings because it just isn't worth reinventing the wheel every time. As long as some care is taken in the approach to wrapping it, I think it's a viable solution.

Finally, I'm not sure what you mean by "support opentracing clients." Interestingly, @rnburn of OpenTracing C++ just created a Lua tracer that is implemented from an underlying C++ tracer and exposed through bindings.

Just know, if there are tiers of clients, Go is clearly the focus and everything else is secondary.

@yurishkuro

This comment has been minimized.

Member

yurishkuro commented Jul 17, 2018

Another major benefit of using wrappers around a C-lib is that those wrappers only need to be implemented once in the OpenTracing community.

@jalberto

This comment has been minimized.

jalberto commented Jul 17, 2018

by supporting OT clients I mean, to "ditch" jaeger client in favour of OT client and join the effort there

@isaachier

This comment has been minimized.

Contributor

isaachier commented Jul 17, 2018

@jalberto Jaeger is an implementation of the OT specification. There is no concrete OT client that I know of in open source other than Jaeger. OT is just an interface, not an implementation.

@jalberto

This comment has been minimized.

jalberto commented Jul 17, 2018

My mistake, I thought the clients here: http://opentracing.io/ has a different code base.

In that case: https://github.com/derailed/ex_ray

@isaachier

This comment has been minimized.

Contributor

isaachier commented Jul 17, 2018

Feel free to use another client. If you know of others interested in supporting this client please let us know.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment