<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Amir Blum</title>
    <description>The latest articles on DEV Community by Amir Blum (@blumamir).</description>
    <link>https://dev.to/blumamir</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F589075%2F7f196809-c9ca-46ae-8d11-c1fcb2dfffb0.jpeg</url>
      <title>DEV Community: Amir Blum</title>
      <link>https://dev.to/blumamir</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/blumamir"/>
    <language>en</language>
    <item>
      <title>Aspecto OpenTelemetry Sampler for NodeJS</title>
      <dc:creator>Amir Blum</dc:creator>
      <pubDate>Mon, 19 Dec 2022 15:17:00 +0000</pubDate>
      <link>https://dev.to/aspecto/aspecto-opentelemetry-sampler-for-nodejs-n7</link>
      <guid>https://dev.to/aspecto/aspecto-opentelemetry-sampler-for-nodejs-n7</guid>
      <description>&lt;p&gt;At &lt;a href="https://www.aspecto.io/?utm_source=dev.to&amp;amp;utm_medium=post&amp;amp;utm_campaign=aspecto-sampler-nodejs"&gt;Aspecto&lt;/a&gt;, we enable users to configure advanced sampling rules (both head and tail sampling) in an easy-to-use UI with reach features and centralized management. It's a control plane for your trace sampling. &lt;/p&gt;

&lt;p&gt;The Aspecto Sampler for NodeJS is an implementation of the OpenTelemetry head sampling that allows you to remotely configure all head sampling needs from one UI with zero code changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Until today, head sampling capabilities were part of our OpenTelemetry distribution, which included a full OpenTelemetry SDK, instrumentations, resource detectors, payload collection, and more. Due to ongoing demand, we are introducing AspectoSampler. Now you can craft your own custom vendor-agnostic OpenTelemetry NodeJS SDK setup and plug the Aspecto sampler with just a few lines of code.&lt;/p&gt;

&lt;p&gt;Here is an example of setting up instrumentation for your typescript service from &lt;a href="https://opentelemetry.io/docs/instrumentation/js/getting-started/nodejs/#setup"&gt;the official OpenTelemetry docs&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/*tracing.ts*/
import * as opentelemetry from "@opentelemetry/sdk-node";
import { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node";
const sdk = new opentelemetry.NodeSDK({
 traceExporter: new opentelemetry.tracing.ConsoleSpanExporter(),
 instrumentations: [getNodeAutoInstrumentations()]
});
sdk.start()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your real-life setup will probably include more components, like resource detectors and an otlp exporter to ship the telemetry data to an OpenTelemetry Collector or your chosen vendor (Aspecto, ahem ahem 👀)&lt;/p&gt;

&lt;p&gt;This simple installation of OpenTelemetry will record &lt;em&gt;all&lt;/em&gt; traces -- each operation going on inside your service. While collecting all spans is fine for POCs, production workloads usually create a firehose of costly and noisy data. &lt;a href="https://www.aspecto.io/product/opentelemetry-sampling/?utm_source=dev.to&amp;amp;utm_medium=post&amp;amp;utm_campaign=aspecto-sampler-nodejs"&gt;Sampling&lt;/a&gt; is a powerful tool in your OpenTelemetry toolbox to reduce your costs and focus on telemetry that is useful for you. Here is the same code with an Aspecto sampler integrated (just two lines of code):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/*tracing.ts*/
import * as opentelemetry from "@opentelemetry/sdk-node";
import { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node";
import { AspectoSampler } from "@aspecto/opentelemetry-sampler";
const sdk = new opentelemetry.NodeSDK({
  traceExporter: new opentelemetry.tracing.ConsoleSpanExporter(),
  instrumentations: [getNodeAutoInstrumentations()],
  sampler: new AspectoSampler(),
});
sdk.start()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is it! Just two lines of code that you will never need to touch again, and you unlocked the FULL power of sampling 🕺&lt;/p&gt;

&lt;p&gt;Now let's see how it works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Plain OpenTelemetry Sampling
&lt;/h2&gt;

&lt;p&gt;Once you realize you collect millions of boring and useless &lt;em&gt;health-check&lt;/em&gt; traces or that active endpoint in your system that floods your trace viewer and blows up your motley bill, you ask yourself -- how do I get rid of them!? And the immediate answer is &lt;em&gt;&lt;a href="https://www.aspecto.io/blog/opentelemetry-sampling-everything-you-need-to-know/?utm_source=dev.to&amp;amp;utm_medium=post&amp;amp;utm_campaign=aspecto-sampler-nodejs"&gt;sampling&lt;/a&gt;&lt;/em&gt;. It is a widely used practice and the ideal go-to solution for this problem.&lt;/p&gt;

&lt;p&gt;OpenTelemetry provides out-of-the-box samplers such as &lt;em&gt;TraceIdRatioBased&lt;/em&gt;. These are great if you want to blindly record a percentage of the traces (sample 1% of spans). &lt;/p&gt;

&lt;p&gt;It is a simple strategy to implement, but despite reducing the overall trace amount, you randomly sample traces while dropping other critical ones, those you &lt;em&gt;always&lt;/em&gt; want to collect.&lt;/p&gt;

&lt;p&gt;After you realize you need more fine-grained control of your sampling, you can write your own custom sampler by implementing the Sampler interface. You might start with something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class MySampler implements Sampler {
  shouldSample(context: Context, traceId: string, spanName: string, spanKind: SpanKind, attributes: Attributes) {
      if (attributes[SemanticAttributes.HTTP_TARGET] === '/health-check') {
          return { decision: SamplingDecision.NOT_RECORD };
      }
      // fallback
      return { decision: SamplingDecision.RECORD_AND_SAMPLED };
  }
  toString() { return 'MySampler'; }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You then wrap with the following, to apply the sampling decision on the entire trace based on its root span.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const sampler = new ParentBasedSampler({ root: new MySampler() });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you test this code, create a PR, get it approved, and deploy it to your dozens of microservices. &lt;/p&gt;

&lt;p&gt;A few days later, your vendor's Billing dashboard already looks happier with fewer spans and less cost.&lt;/p&gt;

&lt;p&gt;Then you browse your Trace Search screen and realize that 95% of your remaining traces come from one heavily used endpoint that gets executed millions of times daily. You still want observability into it but ideally, collect fewer spans than what you do today. You wish you could sample just 1% of this endpoint.&lt;/p&gt;

&lt;p&gt;You might go back to your custom sampler and add something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Sampler, ParentBasedSampler, TraceIdRatioBasedSampler } from '@opentelemetry/sdk-trace-base';
import { SemanticAttributes } from '@opentelemetry/semantic-conventions';
import { Context, SpanKind, Attributes, SamplingDecision } from '@opentelemetry/api';
class MySampler implements Sampler {
  private probabilitySampler = new TraceIdRatioBasedSampler(0.01);
  shouldSample(context: Context, traceId: string, spanName: string, spanKind: SpanKind, attributes: Attributes): SamplingResult {
      if (attributes[SemanticAttributes.HTTP_TARGET] === '/health-check') {
          return { decision: SamplingDecision.NOT_RECORD };
      }
      if ( attributes[SemanticAttributes.HTTP_TARGET] === '/my/busy/endpoint') {
          return this.probabilitySampler.shouldSample(context, traceId);
      }
      // fallback
      return { decision: SamplingDecision.RECORD_AND_SAMPLED };
  }
  toString() { return 'MySampler'; }
}
const sampler = new ParentBasedSampler({ root: new MySampler() });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And again, create a PR, review, merge, deploy, test, and watch your billings drop and your trace viewer becomes less busy. &lt;/p&gt;

&lt;p&gt;At this point, you, your manager, and every other trace consumer in your company are happy, but that is not where the story ends. &lt;/p&gt;

&lt;p&gt;Now, maintaining this sampler becomes one of your tasks. You might need to implement it in multiple languages, add dozens of complex statements, synchronize it across dozens of microservices and serverless functions and debug it when it fails to do what you meant. Requests keep flowing. "I want to see more of this", "can you hide that?", and "why can't I find my trace??"&lt;/p&gt;

&lt;p&gt;One day, an incident in production hits your &lt;em&gt;/my/busy/endpoint.&lt;/em&gt; You say to yourself -- I wish I could see all traces for just a few hours until we understand what is going on. But modifying and deploying new versions is not your first priority, while the incident keeps everyone stressed. &lt;/p&gt;

&lt;p&gt;If you deploy changes in sampling, you need to remember to go back and revert these changes after the incident is resolved.&lt;/p&gt;

&lt;p&gt;This problem does not scale well. Managing sampling for a real-life production environment in code can be a massive headache.&lt;/p&gt;

&lt;p&gt;Introducing Aspecto Sampler 👏🎉&lt;/p&gt;

&lt;h2&gt;
  
  
  Aspecto Sampler
&lt;/h2&gt;

&lt;p&gt;Aspecto has years of experience implementing OpenTelemetry in high-workload production environments. We have collected needs and use cases from our customers and iterated them to crystallize the best-managed sampling mechanism, so you can focus on your task and leave the hard work and technical implementation to us.&lt;/p&gt;

&lt;p&gt;Aspecto sampler abstracts away all the nitty details and implementation code and exposes a UI where you configure the logic in a simple interface. It is basically the sampler from above, but you do not need to write it yourself. Plus, it provides advanced features you can explore to customize your sampling to your specific needs.&lt;/p&gt;

&lt;p&gt;Let's review how it works and its features.&lt;/p&gt;

&lt;h3&gt;
  
  
  Remote Configuration
&lt;/h3&gt;

&lt;p&gt;All sampling configurations are centralized and managed on the Aspecto platform. You only need to install the sampler into your OpenTelemetry SDK once or use our OpenTelemetry distribution and never touch it again.&lt;/p&gt;

&lt;h4&gt;
  
  
  Up-to-date Configuration
&lt;/h4&gt;

&lt;p&gt;Aspecto Sampler always fetches the latest configuration. Sampling configuration is always up-to-date and consistent across all your services. You do not need to deploy any code or worry that some services still run with an old configuration that is not getting updated.&lt;/p&gt;

&lt;h4&gt;
  
  
  Automatic Updates
&lt;/h4&gt;

&lt;p&gt;Your changes are immediately and automatically pushed to all your samplers in seconds. With one click, all your services are updated live. No need to restart, deploy or monitor anything.&lt;/p&gt;

&lt;h4&gt;
  
  
  No Code
&lt;/h4&gt;

&lt;p&gt;Adding, updating, or removing sampling rules does not require any code changes. It is all done in an easy-to-use UI and involves zero code. Any function in your organization can manage it, not only developers who master a specific programming language.&lt;/p&gt;

&lt;h4&gt;
  
  
  Instant
&lt;/h4&gt;

&lt;p&gt;Any change takes effect immediately. You can experiment and fine-tune your configurations and get fast feedback.&lt;/p&gt;

&lt;h3&gt;
  
  
  UI
&lt;/h3&gt;

&lt;p&gt;The entire sampling workflow is managed and configured in a dedicated UI in the Aspecto app, built to give you focused and easy yet powerful tools to achieve your sampling goals.&lt;/p&gt;

&lt;h4&gt;
  
  
  Multiple Languages
&lt;/h4&gt;

&lt;p&gt;One unified interface to customize your sampling for multiple programming languages. No need to master or jump between languages to implement a sampling policy in your organization.&lt;/p&gt;

&lt;h4&gt;
  
  
  Timer Rules
&lt;/h4&gt;

&lt;p&gt;If you are debugging something or working on a specific service or endpoint, it is convenient to "sample everything" while you need it, but you also do not want to forget about it and see your tracing costs inflate. You can add rules with a timer -- so you get instant visibility into the desired area and sleep well knowing that your traces bill will not blow up.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kXMHCY1S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.aspecto.io/wp-content/uploads/2022/12/Group-2422-1-1024x558.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kXMHCY1S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.aspecto.io/wp-content/uploads/2022/12/Group-2422-1-1024x558.png" alt="Aspecto head sampling Timer Rules" width="880" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Turn Rules On and Off
&lt;/h4&gt;

&lt;p&gt;With a single click, you can turn a rule on and off, dynamically adapting sampling as you go and integrating sampling tools into your everyday workflow to find the right balance between costs and telemetry verbosity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5XStnhb1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.aspecto.io/wp-content/uploads/2022/12/head-sampling-Turn-Rules-On-and-Off-1-1024x230.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5XStnhb1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.aspecto.io/wp-content/uploads/2022/12/head-sampling-Turn-Rules-On-and-Off-1-1024x230.png" alt="Aspecto head sampling Turn Rules On and Off" width="880" height="198"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Search Capabilities
&lt;/h4&gt;

&lt;p&gt;OpenTelemetry implementation can easily include many sampling rules. Search your rules with free text to quickly find what you need. You can sort them and check who added each rule and when.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rich Sampling Language
&lt;/h3&gt;

&lt;p&gt;Define your sampling strategy with rules, which are evaluated in order to derive a sampling decision for each new trace.&lt;/p&gt;

&lt;h4&gt;
  
  
  Conditions
&lt;/h4&gt;

&lt;p&gt;Use span attributes like http path, http method, messaging queue or topic name, or any custom span attribute to add conditions. Describe each one with a rich set of operators, such as HTTP path starts with "&lt;em&gt;/user&lt;/em&gt;" or even write regular expressions for parameterized routes like &lt;code&gt;*/account/:id/users*&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--feiUdzj0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.aspecto.io/wp-content/uploads/2022/12/head-sampling-http-path-1024x557.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--feiUdzj0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.aspecto.io/wp-content/uploads/2022/12/head-sampling-http-path-1024x557.png" alt="Aspecto head sampling Conditions" width="880" height="479"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Services and Environments
&lt;/h4&gt;

&lt;p&gt;Narrow a rule to affect only a specific service/s or environment. For example, you can easily add a rule that only affects the users-service in the production environment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GDrHGA-D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.aspecto.io/wp-content/uploads/2022/12/head-sampling-conditions-1024x560.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GDrHGA-D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.aspecto.io/wp-content/uploads/2022/12/head-sampling-conditions-1024x560.png" alt="Aspecto head sampling Services and Environments" width="880" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Sampling Rates and Priority
&lt;/h4&gt;

&lt;p&gt;Arrange your rules according to priorities, place-specific important rules on top, and general fallback rules at the bottom. Each rule defines a sampling rate that can be 0% (record nothing).&lt;/p&gt;

&lt;h3&gt;
  
  
  Installation Instructions
&lt;/h3&gt;

&lt;p&gt;Visit &lt;a href="https://docs.aspecto.io/v1/send-tracing-data-to-aspecto/opentelemetry/nodejs/aspecto-sampler?utm_source=dev.to&amp;amp;utm_medium=post&amp;amp;utm_campaign=aspecto-sampler-nodejs"&gt;our docs&lt;/a&gt; for complete instructions on installation and configuration.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aspecto.io/v1/send-tracing-data-to-aspecto/opentelemetry/nodejs/aspecto-sampler?utm_source=dev.to&amp;amp;utm_medium=post&amp;amp;utm_campaign=aspecto-sampler-nodejs"&gt;SAMPLER DOCS&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Tail Sampling
&lt;/h3&gt;

&lt;p&gt;The sampler above is a Head Sampler that applies sampling decisions in the SDK as spans are created. &lt;/p&gt;

&lt;p&gt;A popular alternative is to use the Aspecto Tail Sampler -- an OpenTelemetry Collector distribution that aggregates spans into traces and applies a sampling decision on an entire trace. Each option has pros and cons, and we encourage you to research and choose the option that best fits your needs. &lt;/p&gt;

&lt;p&gt;Not sure what to choose? &lt;a href="https://calendly.com/eran-18/60min"&gt;Schedule a call&lt;/a&gt; with our OpenTelemetry experts to assist in the process.&lt;/p&gt;

&lt;h3&gt;
  
  
  Feedback
&lt;/h3&gt;

&lt;p&gt;We are in a constant process of learning and improving and would love to hear from you. Do not hesitate to &lt;a href="https://www.aspecto.io/contact-us/?utm_source=dev.to&amp;amp;utm_medium=post&amp;amp;utm_campaign=aspecto-sampler-nodejs"&gt;contact us&lt;/a&gt; (also via our website chat) to share feedback / ask questions / or get support for our managed sampling product. &lt;/p&gt;

&lt;p&gt;Our OpenTelemetry experts are here for you.&lt;/p&gt;

&lt;h3&gt;
  
  
  Supported Languages
&lt;/h3&gt;

&lt;p&gt;Our managed sampler has the following support:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  NodeJS -- integrated with our OpenTelemetry distribution, or as a standalone sampler which you can integrate into your custom opentelemetry setup&lt;/li&gt;
&lt;li&gt;  Ruby -- integrated into our Ruby OpenTelemetry distribution&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Support for more languages is coming soon.&lt;/p&gt;

&lt;p&gt;Our Tail Sampler can be used with any OpenTelemetry SDK and components that produce trace data.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Running Jaeger Locally: How to Get Started</title>
      <dc:creator>Amir Blum</dc:creator>
      <pubDate>Thu, 08 Jul 2021 14:33:22 +0000</pubDate>
      <link>https://dev.to/aspecto/running-jaeger-locally-how-to-get-started-51g3</link>
      <guid>https://dev.to/aspecto/running-jaeger-locally-how-to-get-started-51g3</guid>
      <description>&lt;p&gt;In this article, you’ll learn how to run Jaeger locally, why and when you should do it, as well as what are Jaeger’s limitations when running locally.&lt;/p&gt;

&lt;p&gt;Let’s start with the basics: a distributed tracing system is generally composed of client and backend components.&lt;/p&gt;

&lt;p&gt;I will touch briefly on client components, though most of this post is about backend components.&lt;/p&gt;

&lt;h2&gt;
  
  
  Client Components
&lt;/h2&gt;

&lt;p&gt;The client part is usually a set of libraries installed inside an application which “instrument” it — generating a “span” object for each interesting event happening in runtime inside the service.&lt;/p&gt;

&lt;p&gt;A modern and recommended open-source client SDK that does that is &lt;a href="https://opentelemetry.io/" rel="noopener noreferrer"&gt;OpenTelemetry&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Spans on the client alone are meaningless — they need to be accessible to a person who consumes them. Consumers are usually dev-ops teams monitoring a system or developers maintaining the system and adding new features.&lt;/p&gt;

&lt;h3&gt;
  
  
  Trace Usages
&lt;/h3&gt;

&lt;p&gt;There are many ways in which collected trace data can be used and provide value. These are the common ones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Aggregate spans to trace — group all spans (events) which are part of the same trace (logical operation) arriving from different distributed services, into a single entity&lt;/li&gt;
&lt;li&gt;Query the collected data (show me all traces in the last hour starting at endpoint &lt;code&gt;GET /users&lt;/code&gt; in service X)&lt;/li&gt;
&lt;li&gt;Visualize the data — usually in a graph, or timeline&lt;/li&gt;
&lt;li&gt;Find errors (exceptions, 500s, etc) and investigate their root-cause&lt;/li&gt;
&lt;li&gt;Investigate performance bottlenecks&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Backend Components
&lt;/h2&gt;

&lt;p&gt;To fulfill the requirements above, we need to set up backend components.&lt;/p&gt;

&lt;p&gt;They are used to collect spans from client components, process them, store them in a database, expose an API for the data and UI to view traces and perform queries.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.jaegertracing.io/" rel="noopener noreferrer"&gt;Jaeger&lt;/a&gt; (a &lt;a href="https://www.cncf.io/" rel="noopener noreferrer"&gt;CNCF&lt;/a&gt; graduated project) is a popular open-source project with backend components that does that and is easy to set up.&lt;/p&gt;

&lt;p&gt;To use Jaeger in production, it is recommended to install it in a cloud environment with load-balancing, auto-scaling, replications, and all that jazz.&lt;/p&gt;

&lt;p&gt;However, it is sometimes enough to just run it locally in a lightweight and simple setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running Locally
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.jaegertracing.io/docs/1.23/getting-started/" rel="noopener noreferrer"&gt;The recommended&lt;/a&gt; approach for running Jaeger backend locally is to use docker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker run -d --name jaeger \
  -e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \
  -p 5775:5775/udp \
  -p 6831:6831/udp \
  -p 6832:6832/udp \
  -p 5778:5778 \
  -p 16686:16686 \
  -p 14268:14268 \
  -p 14250:14250 \
  -p 9411:9411 \
  jaegertracing/all-in-one:1.23
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And access the UI in &lt;a href="http://localhost:16686" rel="noopener noreferrer"&gt;http://localhost:16686&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can then configure an Opentelemetry Client SDK installation or &lt;a href="https://github.com/open-telemetry/opentelemetry-collector" rel="noopener noreferrer"&gt;OpenTelemetry Collector&lt;/a&gt; to use Jaeger exporter and send trace data to this local Jaeger.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { NodeTracerProvider } from "@opentelemetry/node";
import { SimpleSpanProcessor } from "@opentelemetry/tracing";
import { JaegerExporter } from "@opentelemetry/exporter-jaeger";

const provider = new NodeTracerProvider();
provider.addSpanProcessor(new SimpleSpanProcessor(new JaegerExporter()));
provider.register();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;(This is how exporting data to local jaeger looks like in nodejs).&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Running Local Jaeger: Benefits
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Faster Debugging
&lt;/h3&gt;

&lt;p&gt;If you work on a service codebase (e.g., fixing a bug, developing a new feature, or implementing integration to other services/databases/messaging systems, etc.), most likely that this is what you do:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You start an instance of the service on your local dev station&lt;/li&gt;
&lt;li&gt;Send traffic to it to test your changes&lt;/li&gt;
&lt;li&gt;Validate the behavior you were expecting&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By instrumenting it locally, you can debug development issues faster.&lt;/p&gt;

&lt;p&gt;For example: find the point in your app where an error occurred with less logging to console, breakpoints, etc.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7mbq1ax2y0mfkt887g2t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7mbq1ax2y0mfkt887g2t.png" alt="An example of a trace in Jaeger showing error while accessing Redis key as a list"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;An example of a trace in Jaeger showing error while accessing Redis key as a list (the red underlines are not part of the Jaeger UI)&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Running Tests
&lt;/h3&gt;

&lt;p&gt;When running your integration test suite locally — if a test fails, it can sometimes be easier to understand what went wrong by examining it in Jaeger UI, where you can view highlighted errors and events organized into a hierarchical structure.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Instrumentation Development
&lt;/h3&gt;

&lt;p&gt;If you are writing a new instrumentation library, observing the tracing output in a UI can be much easier than browsing through textual logs. You can browse the &lt;a href="https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-instrumentation" rel="noopener noreferrer"&gt;JS instrumentation package&lt;/a&gt; for more info and examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running Local Jager: Limitations
&lt;/h2&gt;

&lt;p&gt;Jaeger is free, relatively easy to set up, and will do a good job for most basic setups and tracing needs.&lt;/p&gt;

&lt;p&gt;The UI and features set are quite basic and you may quickly find yourself in the need of &lt;a href="https://www.aspecto.io/compare-jaeger-aspecto/?utm_source=dev.to&amp;amp;utm_medium=post&amp;amp;utm_campaign=why-and-how-to-run-jaeger-locally"&gt;more advanced features&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.aspecto.io/compare-jaeger-aspecto/?utm_source=dev.to&amp;amp;utm_medium=post&amp;amp;utm_campaign=why-and-how-to-run-jaeger-locally"&gt;Other alternatives&lt;/a&gt; can give value and increase development productivity in the following cases:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Lack of End to End Visibility in Async Messaging
&lt;/h3&gt;

&lt;p&gt;When using async messaging systems, generally, there are two cases for traces.&lt;/p&gt;

&lt;p&gt;The first one is when the message broker generates one trace. Jaeger does a great job of displaying us with that one trace. &lt;/p&gt;

&lt;p&gt;The second case, common in batch processing scenarios, is when the senders and receivers in message brokers like Kafka and AWS SQS generate multiple traces (for example, each receive starts a new trace). In this case, Jaeger will display these traces separately. That makes it more complicated to track and debug complex transactions.&lt;/p&gt;

&lt;p&gt;More advanced backends might have an out-of-the-box solution for that and will &lt;a href="https://www.aspecto.io/product/production-troubleshooting/?utm_source=dev.to&amp;amp;utm_medium=post&amp;amp;utm_campaign=why-and-how-to-run-jaeger-locally"&gt;detect it and merge those traces into a single logical flow&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Cross Environment Traces
&lt;/h3&gt;

&lt;p&gt;If your organization works with Jaeger in production, and let’s say you want to use Jaeger to do your tests, sending your local traces to the production Jaeger is highly suboptimal.&lt;/p&gt;

&lt;p&gt;Not only can it pollute the production environment, but it makes it difficult to find your traces within this trace jungle. By running Jaeger locally, you get an isolated playground for your tests and development.&lt;/p&gt;

&lt;p&gt;However, one major pitfall in this scenario is that your local Jaeger will show only the part of the trace generated from your local dev station. It means you lose the context of how your traces communicate and affect downstream and upstream services (i.e., production and staging).&lt;/p&gt;

&lt;p&gt;In this case, &lt;em&gt;you won’t have an isolated and local development session while seeing the full effect of your changes&lt;/em&gt; across the different environments.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Advanced Search
&lt;/h3&gt;

&lt;p&gt;Free text search on all data or based on trace attributes. For example, if you want to search a token in the payload within specific traces.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Trace Data Processing and Insights
&lt;/h3&gt;

&lt;p&gt;Jaeger presents raw traces and highlights errors, however, generating insights based only on that data isn’t trivial and quite complex.&lt;/p&gt;

&lt;p&gt;Examples for such insights can be API breaking change detection, aggregation of traces based on structure, parameter journey in a trace, dependency analysis, comparison to baseline from production or staging, etc.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Enhanced UI
&lt;/h3&gt;

&lt;p&gt;Jaeger UI enumerates all attributes for a span in a long list. It does not group or organizes related data, show JSON content in a tree, highlight common data like HTTP status code, and other good stuff that makes our life easier.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;Running local Jaeger offers great benefits. It is easy to set up, and when it comes to faster debug and running tests, you get this extra confidence you might want when working locally.&lt;/p&gt;

&lt;p&gt;Jaeger is a great tool and does an awesome job answering your basic tracing needs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;However, when your work with services gets a bit more complex, or when you want to take your productivity to the next level when working locally, you might want to &lt;a href="https://www.aspecto.io/compare-jaeger-aspecto/?utm_source=dev.to&amp;amp;utm_medium=post&amp;amp;utm_campaign=why-and-how-to-run-jaeger-locally"&gt;consider other alternatives&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If the limitations I mentioned above are a deal-breaker for you (if not now, they might be in the future), there are several vendors in the market, supplying various solutions which enhance your tracing-based workflow. One that can help you overcome all these issues is Aspecto.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.aspecto.io/?utm_source=dev.to&amp;amp;utm_medium=post&amp;amp;utm_campaign=why-and-how-to-run-jaeger-locally"&gt;Aspecto&lt;/a&gt; gives you everything you get with Jaeger but with enhanced UI, search, and troubleshooting capabilities for &lt;a href="https://www.aspecto.io/product/local-debugging/?utm_source=dev.to&amp;amp;utm_medium=post&amp;amp;utm_campaign=why-and-how-to-run-jaeger-locally"&gt;local development and debugging&lt;/a&gt;. It takes 2 minutes to &lt;a href="(https://www.aspecto.io/?utm_source=dev.to&amp;amp;utm_medium=post&amp;amp;utm_campaign=why-and-how-to-run-jaeger-locally)"&gt;get started&lt;/a&gt; with, it’s free and OpenTelemetry-based. Think of it as Jaeger and Chrome DevTools fusion for your distributed applications.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>microservices</category>
      <category>opensource</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Is Protobuf.js Faster Than JSON?</title>
      <dc:creator>Amir Blum</dc:creator>
      <pubDate>Wed, 21 Apr 2021 13:59:20 +0000</pubDate>
      <link>https://dev.to/aspecto/is-protobuf-js-faster-than-json-ed4</link>
      <guid>https://dev.to/aspecto/is-protobuf-js-faster-than-json-ed4</guid>
      <description>&lt;p&gt;When you have structured data in JavaScript, which needs to be sent over the network (for another microservice, for example) or saved into a storage system, it first needs to be serialized.&lt;/p&gt;

&lt;p&gt;The serialization process converts the data object you have in the JavaScript program memory into a buffer of bytes, which then can be deserialized back into a JavaScript object.&lt;/p&gt;

&lt;p&gt;Two popular serialization methods are JSON and Google Protocol Buffers (Protobuf).&lt;/p&gt;

&lt;h2&gt;
  
  
  JSON
&lt;/h2&gt;

&lt;p&gt;Serializing data to JSON is as easy as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const data = { name: 'foo', age: 30 };
const serialized = JSON.stringify(data); // produce: '{"name":"foo","age":30}'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Protobuf.js
&lt;/h2&gt;

&lt;p&gt;Google Protocol Buffers is a method of serializing structure data based on a scheme (written in .proto file).&lt;/p&gt;

&lt;p&gt;Example of how to serialize the previous payload to Protobuf with the protobufjs package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;syntax = "proto3";
message Message {
    string name = 1;
    uint32 age = 2;
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const protobuf = require("protobufjs");

protobuf.load("message.proto", (err, root) =&amp;gt; {
    if (err)
        throw err;

    const Message = root.lookupType("Message");
    const data = { name: 'foo', age: 30 };
    var errMsg = Message.verify(data);
    if (errMsg)
        throw Error(errMsg);

    const serialized = Message.encode(data).finish(); // produce: &amp;lt;Buffer 0a 03 66 6f 6f 10 1e&amp;gt;
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see that the generated output is only 7 bytes long, much less than the 23 bytes we got on JSON serialization.&lt;/p&gt;

&lt;p&gt;Protobuf can serialize data so compactly mainly because it does not need to embed the field names as text in the data, possibly many times (“name” and “age” in this example are replaced by short descriptors of 2 bytes).&lt;/p&gt;

&lt;h2&gt;
  
  
  Picking the Right Format
&lt;/h2&gt;

&lt;p&gt;Choosing the correct serialization format that works best for you is a task that involves multiple factors.&lt;/p&gt;

&lt;p&gt;JSON is usually easier to debug (the serialized format is human-readable) and easier to work with (no need to define message types, compile them, install additional libraries, etc.).&lt;/p&gt;

&lt;p&gt;Protobuf, on the other hand, usually compresses data better and has built-in protocol documentation via the schema.&lt;/p&gt;

&lt;p&gt;Another major factor is the CPU performance — the time it takes for the library to serialize and deserializes a message. In this post, we want to compare just the performance in JavaScript. &lt;/p&gt;

&lt;p&gt;You might eventually choose a format that is less performant but delivers value in other factors. But if performance might be a big issue for you, well, in that case, keep reading.&lt;/p&gt;

&lt;h2&gt;
  
  
  Encode Performance
&lt;/h2&gt;

&lt;p&gt;At Aspecto, we wrote an &lt;a href="https://docs.aspecto.io/v1/?utm_source=dev.to&amp;amp;utm_medium=post&amp;amp;utm_campaign=json-vs-protobuf"&gt;SDK&lt;/a&gt; that collects trace events and exports them to an OpenTelemetry collector. &lt;/p&gt;

&lt;p&gt;The data is formatted as JSON and sent over HTTP. &lt;/p&gt;

&lt;p&gt;The exporter and collector can also communicate in protobuf using the protobufjs library.&lt;/p&gt;

&lt;p&gt;Since the protobuf format is so compressed, we might think that encoding to protobuf requires less CPU (measured as the number of operations (encode/decode) in a second).&lt;/p&gt;

&lt;p&gt;A quick Google search on the topic strengthens this thesis.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/protobufjs/protobuf.js#performance"&gt;Performance Section in protobufjs documentation&lt;/a&gt; led us to replace our SDK exporter from JSON to protobuf payload, thinking we will get better performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Actual Performance
&lt;/h2&gt;

&lt;p&gt;After changing from JSON serialization to protobuf serialization, we ran our SDK benchmark.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To our surprise, the performance decreased.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That observation, which we first believed was a mistake, sent us to further investigate the issue.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benchmarking — baseline
&lt;/h3&gt;

&lt;p&gt;We first ran the original &lt;a href="https://github.com/protobufjs/protobuf.js/tree/master/bench"&gt;benchmark of protobufjs library&lt;/a&gt; to get a solid starting point. Indeed we got results similar to the library README:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;benchmarking encoding performance ...

protobuf.js (reflect) x 724,119 ops/sec ±0.69% (89 runs sampled)
protobuf.js (static) x 755,818 ops/sec ±0.63% (90 runs sampled)
JSON (string) x 499,217 ops/sec ±4.02% (89 runs sampled)
JSON (buffer) x 394,685 ops/sec ±1.75% (88 runs sampled)
google-protobuf x 376,625 ops/sec ±1.05% (89 runs sampled)


   protobuf.js (static) was fastest
  protobuf.js (reflect) was 4.2% ops/sec slower (factor 1.0)
          JSON (string) was 36.1% ops/sec slower (factor 1.6)
          JSON (buffer) was 48.4% ops/sec slower (factor 1.9)
        google-protobuf was 50.4% ops/sec slower (factor 2.0)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These results show that protobuf.js performance is better than JSON, as opposed to our previous observation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benchmark — telemetry data
&lt;/h2&gt;

&lt;p&gt;We then modified the benchmark to encode our example data which is an &lt;a href="https://github.com/open-telemetry/opentelemetry-proto/blob/main/opentelemetry/proto/trace/v1/trace.proto"&gt;opentelemetry trace data.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We copied the proto files and data to the benchmark and got the following results:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;benchmarking encoding performance ...

protobuf.js (reflect) x 37,357 ops/sec ±0.83% (93 runs sampled)
JSON (string) x 52,952 ops/sec ±2.63% (89 runs sampled)
JSON (buffer) x 45,817 ops/sec ±1.80% (89 runs sampled)

          JSON (string) was fastest
          JSON (buffer) was 12.8% ops/sec slower (factor 1.1)
  protobuf.js (reflect) was 28.2% ops/sec slower (factor 1.4)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These were the results we expected — for this data, protobuf was actually slower than JSON.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benchmark — strings
&lt;/h3&gt;

&lt;p&gt;We got two results for two different data schemas. &lt;/p&gt;

&lt;p&gt;In one – protobufjs was faster, and in the second — JSON was faster. &lt;/p&gt;

&lt;p&gt;Looking at the schemas, the immediate suspect was the number of strings. &lt;/p&gt;

&lt;p&gt;Our schemas were composed almost entirely of strings. So we created a third test, populating a simple schema with many many many strings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;syntax = "proto3";
message TestStringArray {
    repeated string  stringArray = 1;    
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We ran the benchmark with this payload (10,000 strings, of length 10 each).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var payload   = {
    stringArray: Array(10000).fill('0123456789')
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the results proved our suspicion:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;benchmarking encoding performance ...

protobuf.js (reflect) x 866 ops/sec ±0.68% (92 runs sampled)
JSON (string) x 2,411 ops/sec ±0.91% (94 runs sampled)
JSON (buffer) x 1,928 ops/sec ±0.85% (94 runs sampled)

          JSON (string) was fastest
          JSON (buffer) was 20.0% ops/sec slower (factor 1.2)
  protobuf.js (reflect) was 64.0% ops/sec slower (factor 2.8)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When your data is composed of many strings, protobuf performance in JavaScript drops below those of JSON. &lt;/p&gt;

&lt;p&gt;It might be related to JSON.stringify function being implemented in C++ inside V8 engine and highly optimized compared to the JS implementation of protobufjs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Decoding
&lt;/h3&gt;

&lt;p&gt;The benchmarks above are for encoding (serializing). The benchmarks results for decoding (deserializing) are similar.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;If you have the time, our recommendation is to profile your common data, understand the expected performance of each option, and choose the format that works best for your needs.&lt;/p&gt;

&lt;p&gt;It is essential to be aware that protobuf is not necessarily the fastest option. &lt;/p&gt;

&lt;p&gt;If your data is mainly string, then JSON format might be a good choice.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>javascript</category>
      <category>performance</category>
      <category>testing</category>
    </item>
    <item>
      <title>OpenTelemetry KafkaJS Instrumentation for Node.js</title>
      <dc:creator>Amir Blum</dc:creator>
      <pubDate>Wed, 10 Mar 2021 15:23:43 +0000</pubDate>
      <link>https://dev.to/aspecto/opentelemetry-kafkajs-instrumentation-for-node-js-423g</link>
      <guid>https://dev.to/aspecto/opentelemetry-kafkajs-instrumentation-for-node-js-423g</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR — Our JS OpenTelemetry plugin for &lt;code&gt;kafkajs&lt;/code&gt;, is available &lt;a href="https://github.com/aspecto-io/opentelemetry-ext-js/tree/master/packages/instrumentation-kafkajs" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This article describes this plugin for the &lt;code&gt;kafkajs&lt;/code&gt; package and our thought process behind it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Some Background
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://opentelemetry.io/" rel="noopener noreferrer"&gt;OpenTelemetry&lt;/a&gt; is a CNCF project, which, among other things, enables the collection of distributed traces. &lt;/p&gt;

&lt;p&gt;At &lt;a href="https://bit.ly/2OgbrGV" rel="noopener noreferrer"&gt;Aspecto&lt;/a&gt;, we use OpenTelemetry at the core of our product.&lt;/p&gt;

&lt;p&gt;While implementing it in our backend, we found a few plugins that were missing, especially when dealing with asynchronous communication.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One of them was kafkaJS.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We took this opportunity to give back to the community and developed it ourselves. &lt;/p&gt;

&lt;h3&gt;
  
  
  The Plugin
&lt;/h3&gt;

&lt;p&gt;This plugin allows you to track all Kafka interactions in your collected traces, which means, you get a more comprehensive view of your application behavior when using Kafka as a message broker.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;kafkajs&lt;/code&gt; plugin captures &lt;code&gt;producer&lt;/code&gt; and &lt;code&gt;consumer&lt;/code&gt; operations and creates spans according to &lt;a href="https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/semantic_conventions/messaging.md" rel="noopener noreferrer"&gt;the semantic conventions for Messaging Systems&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Each message being produced and consumed is represented by a span with attributes such as &lt;code&gt;messaging.destination&lt;/code&gt;(topic name).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Context is propagated from producers to consumers. When a message is sent to Kafka, the trace will reveal which services consume it and what other cascading operations happen down the pipe.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Batch operations can aggregate multiple messages into a single batch and receive\process them together. This is handled in the plugin according to the specification.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The plugin can be extended with hooks, which enable users to run custom logic for adding span attributes depending on the Kafka message.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwe6g24vells4l5sfj230.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwe6g24vells4l5sfj230.png" alt="simple-trace-example-in-Jaeger-view-Aspecto-opentelemetry-kafkajs-plugin-1024x270.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The above screenshot shows an example of a producer application named &lt;code&gt;kafka-producer&lt;/code&gt;, that exposes an HTTP endpoint (first line), route it in express (second line), and produce two messages to a Kafka topic named &lt;code&gt;test&lt;/code&gt;, which are then consumed by another application called &lt;code&gt;kafka-consumer&lt;/code&gt; .&lt;/p&gt;

&lt;p&gt;As mentioned above, kafkajs was one of the missing plugins we found and as you are reading this we are working to add more plugins.&lt;/p&gt;

&lt;p&gt;Feel free to &lt;a href="https://www.aspecto.io/contact-us/?utm_source=dev-to&amp;amp;utm_medium=post&amp;amp;utm_campaign=kafka-plugin" rel="noopener noreferrer"&gt;reach out to us&lt;/a&gt; with any questions as we are very much invested in OpenTelemetry and the OpenTelementry community.&lt;/p&gt;

</description>
      <category>distributedsystems</category>
      <category>kafka</category>
      <category>opentelemetry</category>
      <category>node</category>
    </item>
    <item>
      <title>How to Reduce RAM Consumption by X6 When Using ts-node</title>
      <dc:creator>Amir Blum</dc:creator>
      <pubDate>Wed, 03 Mar 2021 17:38:44 +0000</pubDate>
      <link>https://dev.to/aspecto/how-to-reduce-ram-consumption-by-6x-when-using-ts-node-4d8p</link>
      <guid>https://dev.to/aspecto/how-to-reduce-ram-consumption-by-6x-when-using-ts-node-4d8p</guid>
      <description>&lt;p&gt;It turns out that running &lt;code&gt;ts-node-dev / ts-node&lt;/code&gt; is constantly consuming hundreds of megabytes of RAM even for small and simple applications.&lt;/p&gt;

&lt;p&gt;In development, it is usually not a big concern, however, it can be, if your application is running inside a docker container with limited resources (for example, with Docker Desktop on Mac which allocates by default only 2GB of RAM to all the containers in total).&lt;/p&gt;

&lt;p&gt;Typescript code should be transpiled to Javascript which can be done either before running the process (tsc) or in runtime (ts-node).&lt;/p&gt;

&lt;p&gt;The most efficient way is transpiling before running, however, this isn’t as developer-friendly since it takes forever. &lt;code&gt;ts-node-dev&lt;/code&gt; loads everything into memory then watches the changes the developer is making and transpiles the project fast on every change.&lt;/p&gt;

&lt;p&gt;We encountered the issue while building a demo application to showcase our product at &lt;a href="https://www.aspecto.io/?utm_source=dev_to&amp;amp;utm_medium=post&amp;amp;utm_campaign=ts-node-ram-consumption"&gt;Aspecto&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We were running multiple typescript services with docker-compose and started seeing arbitrary &lt;code&gt;ts-node-dev&lt;/code&gt; processes exiting without even running the application, displaying the message “Done in 79.06s”.&lt;/p&gt;

&lt;p&gt;This was due to a lack of memory. Each typescript service was using ~600MB of RAM out of the total 2GB available for all containers.&lt;/p&gt;

&lt;p&gt;After digging a bit, we found a few possible solutions and wanted to share them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run ts-node-dev with option &lt;code&gt;--transpile-only&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;In our case, adding the --transpile-only option to ts-node-dev reduced the consumed RAM from ~600MB to ~170MB.&lt;/p&gt;

&lt;p&gt;The price was that the typescript code would only be transpiled, and typechecking would be skipped. Most modern IDEs (vscode, web storm), has built-in typescript IntelliSense which highlights errors, so for us, it was a fair price to pay.&lt;/p&gt;

&lt;p&gt;If you use &lt;code&gt;ts-node&lt;/code&gt; to run code in production that was already successfully compiled and tested in the CI, you can only benefit from setting this option.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compile the code with tsc and monitor file changes with nodemon
&lt;/h2&gt;

&lt;p&gt;Instead of using &lt;code&gt;ts-node-dev&lt;/code&gt;, which consumes a lot of memory, it is possible to compile the application directly with &lt;code&gt;tsc&lt;/code&gt; and then run it from dist/build like this: &lt;code&gt;node dist/index.js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For automatic reload on source file changes, nodemon / node-dev can be used.&lt;/p&gt;

&lt;p&gt;This is our “start” script in package.json:&lt;/p&gt;

&lt;p&gt;For automatic reload on source file changes, &lt;code&gt;nodemon / node-dev&lt;/code&gt; can be used.&lt;/p&gt;

&lt;p&gt;This is our “start” script in package.json:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"scripts": {
  "start": "nodemon --watch src -e ts --exec \"(tsc &amp;amp;&amp;amp; node dist/index.js) || exit 1\""
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach reduced the RAM on our service from ~600MB to ~95MB (but there was still a spike in RAM to 600Mb for few seconds while &lt;code&gt;tsc&lt;/code&gt; was compiling).&lt;/p&gt;

&lt;p&gt;Unlink the previous option, this approach does check for typescript errors and warnings, and the service does not start if errors exist in the code.&lt;/p&gt;

&lt;p&gt;The price to pay here is a longer compilation time. In our setup, it’s about 10 seconds from saving the file until the service restarts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Increase Docker desktop available RAM
&lt;/h2&gt;

&lt;p&gt;This is the easiest fix. Just allocate more Memory to Docker Desktop by going to Preferences =&amp;gt; Resources =&amp;gt; Memory, and increase the value.&lt;/p&gt;

&lt;p&gt;While it fixes the immediate problem, the containers still consume a lot of memory, and if you have plenty of them, it might be a problem soon enough.&lt;/p&gt;

&lt;p&gt;In addition, changing the default configuration should be done by every user that wants to run the system with docker-compose, which introduces complexity in installation and usage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;If memory consumption is not an issue for you, just use &lt;code&gt;ts-node&lt;/code&gt; in production and &lt;code&gt;ts-node-dev&lt;/code&gt; in development.&lt;/p&gt;

&lt;p&gt;However, if you do care about memory, then you have a tradeoff between fast restart time after modifications (but typechecking only in the IDE, set &lt;code&gt;--transpileOnly&lt;/code&gt;, or typechecking in compilation) and slower restart on each modification (directly use &lt;code&gt;tsc&lt;/code&gt; and &lt;code&gt;nodemon&lt;/code&gt; / &lt;code&gt;node-dev&lt;/code&gt; ).&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>microservices</category>
      <category>node</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
