How to receive OTLP exported traces in Rust - node.js

I want to monitor traces of my Node.js application, and I am using #opentelemetry/exporter-trace-otlp-grpc library for this purpose.
Now, I want to receive this traces in a Rust application. Unfortunately, Seems like there is no otlp receiver implementation in Rust as of now !
What is the best possible way (as of now) to collect these traces in my Rust application (preferably based on HTTP or GRPC) ?
Thanks in advance !

Based on your comment, you should rephrase your question. You don't want to receive traces in Rust. What you want is the context propagated from upstream application to your Rust process.
You need to use one of many possible context propagators in your application. If you don't have already I would suggest using W3C context propagation https://www.w3.org/TR/trace-context/. All the SDKs have the implementation of these propagators.
Here is what you would do is to set the global propagator in both the Node and Rust applications and the propagation should be done automatically unless you have some rust application which is not yet supported by OTEL, in which case you need to do it manually.
In JS application
const api = require("#opentelemetry/api");
const { W3CTraceContextPropagator } = require("#opentelemetry/core");
/* Set Global Propagator */
api.propagation.setGlobalPropagator(new W3CTraceContextPropagator());
In Rust application
use opentelemetry::global;
use opentelemetry::sdk::propagation::TraceContextPropagator;
...
global::set_text_map_propagator(TraceContextPropagator::new());
If for some reason your web server/client doesn't support the auto context propagation, given the OTEL rust is not very mature yet. You would have to inject/extract to and from header to achieve the propagation.
Manually Inject
global::get_text_map_propagator(|propagator| {
propagator.inject_context(&cx, &mut your_headers
});
Manually Extract
let parent_cx = global::get_text_map_propagator(|propagator| {
propagator.extract(&HeaderExtractor(req.headers()))
});
span = tracer.start_with_context("foo", &parent_cx);

Related

How can I log span duration with Rust tracing?

Rust has a tracing library that seems quite popular. It uses a building block called "span":
Spans represent periods of time in the execution of a program.
Now that I've set spans all throughout my app, how can I actually log their duration?
I've so far found:
tracing-timing. Great, but a bit elaborate, printing whole histogram, when I'd like simple durations.
tracing-tree. This one is really close to what I'm looking for, currently set up is failing for me, I'll figure it out, but this one still prints them in a tree, I'm looking more for the plain duration. No tree.
Any way to do that with tracing?
The basic formatting layer from tracing-subscriber is very flexible with what is logged. By default it will only show log events, but there are other events available for spans (new, enter, exit, close). You'd be interested in the logging the "close" events, which indicate when the span has ended and would know the time elapsed from when it started.
You can do this simply using .with_span_events() and FmtSpan::CLOSE. Here's a sample:
[dependencies]
tracing = "0.1.36"
tracing-subscriber = "0.3.15"
use std::time::Duration;
use tracing_subscriber::fmt;
use tracing_subscriber::fmt::format::FmtSpan;
#[tracing::instrument]
fn do_some_work(n: i32) {
std::thread::sleep(Duration::from_millis(100));
if n == 1 {
do_some_more_work();
}
}
#[tracing::instrument]
fn do_some_more_work() {
std::thread::sleep(Duration::from_millis(100));
}
fn main() {
fmt::fmt()
.with_span_events(FmtSpan::CLOSE)
.with_target(false)
.with_level(false)
.init();
for n in 0..3 {
do_some_work(n);
}
}
2022-09-14T15:47:01.684149Z do_some_work{n=0}: close time.busy=110ms time.idle=5.10µs
2022-09-14T15:47:01.904656Z do_some_work{n=1}:do_some_more_work: close time.busy=109ms time.idle=3.00µs
2022-09-14T15:47:01.904986Z do_some_work{n=1}: close time.busy=220ms time.idle=1.60µs
2022-09-14T15:47:02.014846Z do_some_work{n=2}: close time.busy=110ms time.idle=2.20µs
You can customize it to your liking further with other methods or by creating a custom FormatEvent implementation.
I do want to mention that tracing is "a framework for instrumenting Rust programs to collect structured, event-based diagnostic information." While function timing is part of that diagnostic information, it is designed in a way to collect that information in the field. If you're trying to assess the performance of your code in a synthetic environment, I'd encourage you to use a more robust benchmarking library like criterion.

How do I test cross-thread queue?

I am not 100% sure that this is SO-adequate question, but I guess it
falls under "a specific programming problem". Tips to make it
more SO-friendly are welcome.
A bit of context
In DLang there is no default data sharing between threads - instead we use message passing. As safe and clean that approach is, it makes it hard to scale our code horizontaly. Best example is multiple writer - multiple reader problem - it gets quite complicated when using std.concurrency.
Quite common way to solve that problem is to use an in-memory queue - writers push to that queue, readers pull from it, each thread runs on its own pace, and Bob's your uncle. So, I've decided to implement Queue for DLang myself.
The code
Queue has following API:
module javaesque.concurrency;
Queue!T queue(T)(){
// constructor, out of struct itself for implementation sake
}
struct Queue(T){
// internals not important for the sake of question
void push(T val){
// ...
}
T pull(){
// ...
}
}
And here's a sample app using that:
// import whatever's needed, stdio, concurrency, etc
void runnable(Queue!string q){
try {
while (true) {
writeln(to!string(thisTid)~" "~q.pull());
}
} catch (OwnerTerminated ot) {
}
}
void main(string[] args){
Queue!string queue = queue!string();
spawn(&runnable, queue);
spawn(&runnable, queue);
for (int i = 0; i< 20; ++i){
queue.push(to!string(i));
}
readln();
}
Question
OK, so how do I test that? While prototyping I just tested it by running that sample app, but now that I've confirmed that the idea itself may work as expected, I want to write some unit tests. But how?
Please keep in mind that I didn't add dlang or related tags to this
question. Even though I've supplied snippets in DLang and the
background is highly D-related, I am looking for general help on
testing this kind of structures, without constraining myself to this
language. Obviously, general answer with DLang-specific addition is
welcome, but the question itself should be treated as
language-agnostic.
Well, the "generic" approach to testing is two-fold:
you focus on the public contract of your constructs, and think up testcases that test each aspect of that contract
you focus on the inner implementation and think of (additional) test cases to get you into specific corner cases
And beyond that: you obviously first test the whole construct in a single threaded manner. You could also look into similar things as a same thread service: you setup your environment to effectively use one thread only.
That might be sufficient for "most" of your code - then you might be fine with some few "integration" tests that actually test one expected end to end scenario (using multiple threads). There you could test for example that your multiple readers receive some expected result in the end.
Finally, from another angle: the key to good unit tests is to write code that can be unit tested easily. You need to be able actually look at your different units in isolation. But if you would provide that code here, that would rather turn into a codereview request (which wouldnt belong here).

node, require, singleton or not singleton?

I was pretty shocked to find out that "require" in node creates a singleton by default. One might assume that many people have modules which they require which have state, but are created as a singleton, so break the app as soon as there are multiple concurrent users.
We have the opposite problem, requires is creating a non-singleton, and we dont know how to fix this.
Because my brain is wired as a java developer, all our node files/modules are defined thusly:
file playerService.js
const Player = require("./player")
class PlayerService {
constructor(timeout) {
// some stuff
}
updatePlayer(player) {
// logic to lookup player in local array and change it for dev version.
// test version would lookup player in DB and update it.
}
}
module.exports = PlayerService
When we want to use it, we do this:
someHandler.js
const PlayerService = require("./playerService")
const SomeService = require("./someService")
playerService = new PlayerService(3000)
// some code which gets a player
playerService.updatePlayer(somePlayer)
Although requires() creates singletons by default, in the above case, I am guessing it is not creating a singleton as each websocket message (in our case) will instantiate a new objects in every module which is called in the stack. That is a lot of overhead - to service a single message, the service might get instantiated 5 times as there are 5 different sub services/helper classes which call each other and all do a requires(), and then multiply this by the number of concurrent users and you get a lot of unnecessary object creation.
1) How do we modify the above class to work as a singleton, as services don't have state?
2) Is there any concept of a global import or creating a global object, such that we can import (aka require) and/or instantiate an object once for a particular websocket connection and/or for all connections? We have no index.js or similar. It seems crazy to have to re-require the dependent modules/files for every js file in a stack. Note, we looked at DI options, but found them too arcane to comprehend how to use them as we are not js gurus, despite years of trying.
You can simply create an instance inside the file and export it.
let playerService = new PlayerService();
module.exports = playerService;
In this case, you may want to add setters for the member variables you would take as constructor parameters to ensure encapsulation.
Also note that, creating object instances with new in javascript is cheaper than traditional OOP language because of it's prototype model (more).
So don't hesitate when you really need new instances (as seen in your code, do you really want to share the timeout constructor parameter?), since javascript objects are pretty memory efficient with prototype methods and modern engines has excellent garbage collectors to prevent memory leak.

How does NodeJS handle multi-core concurrency?

Currently I am working on a database that is updated by another java application, but need a NodeJS application to provide Restful API for website use. To maximize the performance of NodeJS application, it is clustered and running in a multi-core processor.
However, from my understanding, a clustered NodeJS application has a their own event loop on each CPU core, if so, does that mean, with cluster architect, NodeJS will have to face traditional concurrency issues like in other multi-threading architect, for example, writing to same object which is not writing protected? Or even worse, since it is multi-process running at same time, not threads within a process blocked by another...
I have been searching Internet, but seems nobody cares that at all. Can anyone explain the cluster architect of NodeJS? Thanks very much
Add on:
Just to clarify, I am using express, it is not like running multiple instances on different ports, it is actually listening on the same port, but has one process on each CPUs competing to handle requests...
the typical problem I am wondering now is: a request to update Object A base on given Object B(not finish), another request to update Object A again with given Object C (finish before first request)...then the result would base on Object B rather than C, because first request actually finishes after the second one.
This will not be problem in real single-threaded application, because second one will always be executed after first request...
The core of your question is:
NodeJS will have to face traditional concurrency issues like in other multi-threading architect, for example, writing to same object which is not writing protected?
The answer is that that scenario is usually not possible because node.js processes don't share memory. ObjectA, ObjectB and ObjectC in process A are different from ObjectA, ObjectB and ObjectC in process B. And since each process are single-threaded contention cannot happen. This is the main reason you find that there are no semaphore or mutex modules shipped with node.js. Also, there are no threading modules shipped with node.js
This also explains why "nobody cares". Because they assume it can't happen.
The problem with node.js clusters is one of caching. Because ObjectA in process A and ObjectA in process B are completely different objects, they will have completely different data. The traditional solution to this is of course not to store dynamic state in your application but to store them in the database instead (or memcache). It's also possible to implement your own cache/data synchronization scheme in your code if you want. That's how database clusters work after all.
Of course node, being a program written in C, can be easily extended in C and there are modules on npm that implement threads, mutex and shared memory. If you deliberately choose to go against node.js/javascript design philosophy then it is your responsibility to ensure nothing goes wrong.
Additional answer:
a request to update Object A base on given Object B(not finish), another request to update Object A again with given Object C (finish before first request)...then the result would base on Object B rather than C, because first request actually finishes after the second one.
This will not be problem in real single-threaded application, because second one will always be executed after first request...
First of all, let me clear up a misconception you're having. That this is not a problem for a real single-threaded application. Here's a single-threaded application in pseudocode:
function main () {
timeout = FOREVER
readFd = []
writeFd = []
databaseSock1 = socket(DATABASE_IP,DATABASE_PORT)
send(databaseSock1,UPDATE_OBJECT_B)
databaseSock2 = socket(DATABASE_IP,DATABASE_PORT)
send(databaseSock2,UPDATE_OPJECT_C)
push(readFd,databaseSock1)
push(readFd,databaseSock2)
while(1) {
event = select(readFD,writeFD,timeout)
if (event) {
for (i=0; i<length(readFD); i++) {
if (readable(readFD[i]) {
data = read(readFD[i])
if (data == OBJECT_B_UPDATED) {
update(objectA,objectB)
}
if (data == OBJECT_C_UPDATED) {
update(objectA,objectC)
}
}
}
}
}
}
As you can see, there's no threads in the program above, just asynchronous I/O using the select system call. The program above can easily be translated directly into single-threaded C or Java etc. (indeed, something similar to it is at the core of the javascript event loop).
However, if the response to UPDATE_OBJECT_C arrives before the response to UPDATE_OBJECT_B the final state would be that objectA is updated based on the value of objectB instead of objectC.
No asynchronous single-threaded program is immune to this in any language and node.js is no exception.
Note however that you don't end up in a corrupted state (though you do end up in an unexpected state). Multithreaded programs are worse off because without locks/semaphores/mutexes the call to update(objectA,objectB) can be interrupted by the call to update(objectA,objectC) and objectA will be corrupted. This is what you don't have to worry about in single-threaded apps and you won't have to worry about it in node.js.
If you need strict temporally sequential updates you still need to either wait for the first update to finish, flag the first update as invalid or generate error for the second update. Typically for web apps (like stackoverflow) an error would be returned (for example if you try to submit a comment while someone else have already updated the comments).

performance of wglGetProcAddress, should calls be cached?

There is a simple code inside a function (from a legacy library) used in init phase - for instance in a Texture Loader module.
loadTexture() {
// ...
gl_func = wglGetProcAddress(...)
// ...
gl_func()
}
Should I worry about the cost of wglGetProcAddresscall? Or maybe it is so fast that no caching mechanism is needed? Or maybe WGL caches such calls for the process?
What about other similar functions from GLX and Apple? Should I worry or not about them as well?
wglGetProcAddress will at least do some string comparisons so it's not free. The big issue is that your code will be ugly if you insert wglGetProcAddress every time you use a gl function.
It's best if you use a generator that puts all the ugly wglGetProcAddress in a separate file. For example using glux or glloadgen.

Resources