aster.cloud aster.cloud
  • /
  • Platforms
    • Public Cloud
    • On-Premise
    • Hybrid Cloud
    • Data
  • Architecture
    • Design
    • Solutions
    • Enterprise
  • Engineering
    • Automation
    • Software Engineering
    • Project Management
    • DevOps
  • Programming
    • Learning
  • Tools
  • About
  • /
  • Platforms
    • Public Cloud
    • On-Premise
    • Hybrid Cloud
    • Data
  • Architecture
    • Design
    • Solutions
    • Enterprise
  • Engineering
    • Automation
    • Software Engineering
    • Project Management
    • DevOps
  • Programming
    • Learning
  • Tools
  • About
aster.cloud aster.cloud
  • /
  • Platforms
    • Public Cloud
    • On-Premise
    • Hybrid Cloud
    • Data
  • Architecture
    • Design
    • Solutions
    • Enterprise
  • Engineering
    • Automation
    • Software Engineering
    • Project Management
    • DevOps
  • Programming
    • Learning
  • Tools
  • About
  • Cloud-Native
  • Programming

How OpenTelemetry Works Under The Hood In JavaScript

  • aster.cloud
  • September 11, 2022
  • 5 minute read

OpenTelemetry (OTel) is an open source selection of tools, SDKs and APIs, that allows developers to collect and export traces, metrics and logs. It’s the second-most active project in the CNCF, and is emerging as the industry standard for system observability and distributed tracing across cloud-native and distributed architectures. OTel supports multiple languages, like JavaScript, Java, Python, Go, Ruby and C++. Many developers, however, aren’t familiar with the actual technology behind OTel – how does this magic actually works behind the scenes? In this blog post, I will explain how OpenTelemetry works under the hood with JavaScript. In the future, we will show OTel in action in additional languages.

Instrumentation Under the Hood: A Technical Explanation

Like all instrumentation libraries, OpenTelemetry operates by wrapping existing function implementations and extracting the necessary pieces of data. These include the function parameters, duration, and results. Sometimes, changes to the data are made as well (e.g., for context propagation purposes) , in a cautious manner.


Partner with aster.cloud
for your next big idea.
Let us know here.



From our partners:

CITI.IO :: Business. Institutions. Society. Global Political Economy.
CYBERPOGO.COM :: For the Arts, Sciences, and Technology.
DADAHACKS.COM :: Parenting For The Rest Of Us.
ZEDISTA.COM :: Entertainment. Sports. Culture. Escape.
TAKUMAKU.COM :: For The Hearth And Home.
ASTER.CLOUD :: From The Cloud And Beyond.
LIWAIWAI.COM :: Intelligence, Inside and Outside.
GLOBALCLOUDPLATFORMS.COM :: For The World's Computing Needs.
FIREGULAMAN.COM :: For The Fire In The Belly Of The Coder.
ASTERCASTER.COM :: Supra Astra. Beyond The Stars.
BARTDAY.COM :: Prosperity For Everyone.

The specific wrapping and extraction mechanism operates differently in every language. There is a clear difference between how it works in dynamic languages, like JavaScript, Python and Ruby, and non-dynamic languages, like Java, Go and .NET (but more on that later).

Let’s think of a classic example. Say we are trying to collect data from an HTTP client (like axios in JavaScript or requests in Python). For simplicity’s sake, let’s assume we only want to collect the request duration, HTTP method, URL and response status code.

Python’s requests lib, for example, exposes a separate function for each HTTP method (requests.get / requests.post / requests.put, and so on). But each of these functions eventually calls an internal request method, whose parameters are the method, URL and all the kwargs arguments. The function then returns a response object.

Read More  Exploring Cilium Layer 7 Capabilities Compared To Istio

A simplified way of explaining how instrumenting requests would look something like:

<strong>def</strong> <strong>request</strong>(method, url, **kwargs):
	<em># Original implementation</em>

<strong>def</strong> <strong>wrapped_request</strong>(method, url, **kwargs):
	before = datetime.now()
	<em># Call the original implementation</em>
	response = request(method, url, **kwargs)
	<em># Collect the necessary information, asynchronously of course</em>
	duration = datetime.now() - before
	collect_data(method, url, response.status_code, duration)
	<em># Return the value from the original call</em>
	<strong>return</strong> response

To close the loop, the original function implementation only needs to be replaced with the new one, wrapped_request. For dynamic languages like JS and Python, this is done by simply holding a reference to the original implementation and replacing the function by its name. A pseudocode implementation (which isn’t very very far from a real life code ) looks like this:

original_request_impl = requests.request

<strong>def</strong> <strong>wrapped_request</strong>(method, url, **kwargs):
	<em># Wrapped implementation as appears, has the original as a closure</em>

requests.request = wrapped_requests

Users of these requests will not notice a thing – they will continue calling requests.get and requests.post like they did before. But the auto-instrumentation will collect the necessary data for monitoring, troubleshooting and many other use cases.

How Does Instrumentation Work in JavaScript?

In JS, since everything is an object, patching a method is as easy as reassigning a variable. Let’s look at a simple example:

<strong>class</strong> Person {
	constructor(name) {
		<strong>this</strong>.name = name;
	}

	print() {
		console.log(`My name is ${<strong>this</strong>.name}`)
	}
}


<strong>const</strong> p = <strong>new</strong> Person(‘Johnny’);
p.print(); <em>// Prints “My name is Johnny”</em>
<strong>const</strong> origPrint = p.print;
<strong>const</strong> newPrint = <strong>function</strong>() {
	console.log(‘Hey there!’);
	<em>// Call the original implementation</em>
	origPrint.apply(<strong>this</strong>, arguments);
}
p.print = newPrint;
p.print(); <em>// Prints “Hey there! My name is Johnny”</em>

What we did was simple – we replaced the implementation of the specific Person instance, and added an additional print, to show how the instrumentation works. As a side note, notice that this code change only affects the specific instance of the Person class. To patch all instances, we could have simply replaced the print method of Person.prototype instead.

How OpenTelemetry Works with JavaScript

In JavaScript, OpenTelemetry works specifically by hooking into the native require function. This is the function that loads modules by their name, triggering the instrumentation process. For example, when the developer calls require('kafkajs'), OTel uses the require-in-the-middle module to apply changes to the `kafkajs` module. This change wraps the necessary functions in a similar manner as shown above, using the shimmer library, and returns the patched module back to the user code. From the end-user’s perspective – the change was completely transparent and they are not aware of any changes made.

Read More  Support For 100 Large-Scale Clusters

You may have noticed that this mechanism implicitly assumes that the `require-in-the-middle` hook was set before the call to require('kafkajs'). If `kafkajs` (or any other module we are trying to instrument) is loaded before the hook is set, it will simply “miss” its opportunity to patch the necessary functions. This is a big potential pitfall – it assumes the developer knows exactly where to put the OpenTelemetry initialization code. In many cases – this may not be trivial, and we have indeed seen many developers “misplace” the OTel initialization code, causing the instrumentation to behave unexpectedly. Data from modules that were required before OTel are missing (typically, HTTP frameworks like express/koa), while data from other modules appear properly.

How is this problem solved?

Ensuring OTel is Loaded Before Other JavaScript Modules

As described above, using OpenTelemetry in JS requires a good understanding of the application’s initialization flow. A module that is loaded before OTel will not be properly instrumented, and it is often happening implicitly through cascading requires. But how can you be 100% sure the module was loaded after OTel?

In some cases (AWS Lambda, for instance) the developer may not even have control over the loaded modules, as the Lambda runtime comes with preloaded modules and calls a handler function that the developer provides. In this case, adding the initialization code at the top of the handler file just won’t work. There are other similar examples – where the code runs as part of homegrown microservices templates, whose initialization flow isn’t accessible (and perhaps even known) to the developer.

Read More  A New Look For The Red Pin On Maps JavaScript, Android And iOS

The most reliable way to avoid these problem is to use the native Node.js functionality of –require – to make sure the OTel initialization code is called before anything else. Setting NODE_OPTIONS to require this code ensures no module is loaded before the require-in-the-middle hook. The typical way for doing this is by creating a file with the OpenTelemetry initialization code (let’s call it otel_init.js). Assuming the application’s main file is app.js, you can either:

  1. Replace the node app.js command with node --require otel_init.js app.js.
  2. If you’re unable (or prefer not to) change the command, setting the NODE_OPTIONS environment variable to --require otel_init.js will also do the trick.

What about cases in which require-in-the-middle cannot work at all? webpack bundles the entire module with all of its dependencies into a single file, and the modules are not loaded using the native require function (except for modules that are defined externally), but rather by a unique identifier allocated by webpack.

How can OTel work in such conditions? Stay tuned for our next blog posts.

To learn the basic usage of OTEl with JavaScript, click here.

To get started with Helios, which leverages OTel’s capabilities to help engineering teams build production-ready cloud-native applications, sign up here.

 

Guest post originally published on the Helios blog by Ran Nozik
Source CNCF


For enquiries, product placements, sponsorships, and collaborations, connect with us at [email protected]. We'd love to hear from you!

Our humans need coffee too! Your support is highly appreciated, thank you!

aster.cloud

Related Topics
  • CNCF
  • javascript
  • OpenTelemetry
  • OTel
You May Also Like
aster-cloud-sms-pexels-tim-samuel-6697306
View Post
  • Programming
  • Software

Send SMS texts with Amazon’s SNS simple notification service

  • July 1, 2025
aster-cloud-website-pexels-goumbik-574069
View Post
  • Programming
  • Software

Host a static website on AWS with Amazon S3 and Route 53

  • June 27, 2025
View Post
  • Cloud-Native
  • Multi-Cloud

Oracle Expands Multicloud Capabilities with AWS, Google Cloud, and Microsoft Azure

  • September 11, 2024
Cloud computing concept image double exposure Digitally Enhanced Smart City Concept with Cloud Computing
View Post
  • Cloud-Native
  • Computing
  • Hybrid Cloud
  • Multi-Cloud
  • Public Cloud

Make Your Business Resilient By Integrating These Best Practices Into Your Cloud Architecture

  • July 29, 2024
Huawei Cloud Cairo Region Goes Live
View Post
  • Cloud-Native
  • Computing
  • Platforms

Huawei Cloud Goes Live in Egypt

  • May 24, 2024
View Post
  • Cloud-Native
  • Computing
  • Engineering

10 Cloud Development Gotchas To Watch Out For

  • March 29, 2024
Storage Ceph
View Post
  • Cloud-Native
  • Data

The Growth Of IBM Storage Ceph – The Ideal Foundation For A Modern Data Lakehouse

  • January 30, 2024
Clouds
View Post
  • Cloud-Native
  • Platforms
  • Software Engineering

Microsoft Releases Azure Migrate Assessment Tool For .NET Application

  • January 14, 2024

Stay Connected!
LATEST
  • 1
    Expectations vs. Reality: The AI We Thought We’d Have in 10 Years
    • June 19, 2026
  • digital-nomad-freelancer-worker-2151205464 2
    One paperwork problem – Get your Digital Nomad Visa employment documents fast from UK, EU or Singapore
    • June 16, 2026
  • 3
    Samsung Art Store Brings Art Basel to Homes Worldwide With New Curated Collection
    • June 15, 2026
  • 4
    You Do Not Need to Invest in the IPO of SpaceX, Anthropic, and OpenAI
    • June 10, 2026
  • 5
    The consequences of relying on AI for accurate news
    • June 10, 2026
  • 6
    Connecting AI agents with unstructured data using Google Cloud Storage MCP Servers
    • June 10, 2026
  • 7
    WWDC26: Apple unveils next generation of Apple Intelligence, Siri AI, powerful parental controls, and an expansive set of software improvements
    • June 8, 2026
  • 8
    IBM and Google Cloud Announce Strategic Partnership to Scale AI with Human Expertise and AI‑Powered Delivery
    • June 4, 2026
  • Data center 9
    Data Sovereignty in Spain. It’s Not Just About the Law, It’s About Efficiency
    • June 3, 2026
  • 10
    Ink vs Pixels. What you miss versus what you are actually missing.
    • June 1, 2026
about
Hello World!

We are aster.cloud. We’re created by programmers for programmers.

Our site aims to provide guides, programming tips, reviews, and interesting materials for tech people and those who want to learn in general.

We would like to hear from you.

If you have any feedback, enquiries, or sponsorship request, kindly reach out to us at:

[email protected]
Most Popular
  • 1
    Banks race to patch new cyber vulnerabilities, and other cybersecurity news
    • May 25, 2026
  • pope-leo-xiv-cq5dam-1500.844 2
    Pope Leo XIV to Publish First Encyclical on Artificial Intelligence and Human Dignity on 25 May
    • May 22, 2026
  • 3
    Portfolio to Clients, and is Strengthened by Ongoing Project Glasswing Work
    • May 20, 2026
  • reMarkable Paper Pure 4
    Everything The reMarkable Paper Pure Actually Does
    • May 14, 2026
  • 5
    Scaling cloud and AI: Microsoft Azure’s commitment to Europe’s digital future
    • May 11, 2026
  • /
  • Technology
  • Tools
  • About
  • Contact Us

Input your search keywords and press Enter.