<?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: Luiz Lelis</title>
    <description>The latest articles on DEV Community by Luiz Lelis (@luizhlelis).</description>
    <link>https://dev.to/luizhlelis</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%2F550840%2Fbd689b55-e64a-448b-b9ce-2513405efad6.jpeg</url>
      <title>DEV Community: Luiz Lelis</title>
      <link>https://dev.to/luizhlelis</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/luizhlelis"/>
    <language>en</language>
    <item>
      <title>OpenTelemetry Journey #01 - Important concepts</title>
      <dc:creator>Luiz Lelis</dc:creator>
      <pubDate>Sun, 24 Mar 2024 21:35:08 +0000</pubDate>
      <link>https://dev.to/luizhlelis/opentelemetry-journey-01-important-concepts-2l54</link>
      <guid>https://dev.to/luizhlelis/opentelemetry-journey-01-important-concepts-2l54</guid>
      <description>&lt;p&gt;First of all, let's start with the basics. There are some important concepts to be clarified before we dive into the OpenTelemetry world. The vast majority of the naming conventions and concepts are from projects and papers that inspired OpenTelemetry, such as &lt;a href="https://opentracing.io/"&gt;OpenTracing&lt;/a&gt;, &lt;a href="https://opencensus.io/"&gt;OpenCensus&lt;/a&gt; and &lt;a href="https://research.google/pubs/dapper-a-large-scale-distributed-systems-tracing-infrastructure/"&gt;Dapper&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Observability?
&lt;/h2&gt;

&lt;p&gt;In control theory, observability is a measure of how well the internal states of a system can be inferred from knowledge of its external outputs. Making a relationship with software systems, observability is the ability to understand the internal state of a system by examining telemetry data. This telemetry data is what we call signals.&lt;/p&gt;

&lt;p&gt;In order to understand the internal state of a system, the application must be properly instrumented to emit signals enough to provide a clear picture of what is happening.&lt;/p&gt;

&lt;h2&gt;
  
  
  Context propagation
&lt;/h2&gt;

&lt;p&gt;Context propagation is the mechanism that allows the correlation of signals emitted by different parts of a system. It is essential to understand the flow of a request through a distributed system.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcp9cc3o77lkep4ibj9jw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcp9cc3o77lkep4ibj9jw.png" alt="context-propagation" width="800" height="320"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Basically, to propagate a context, the upstream service must inject the context into the request, and the downstream service must extract the context from the request. That propagation is handled by the instrumentation libraries, but can be manually implemented as well through the Propagation APIs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Spans
&lt;/h2&gt;

&lt;p&gt;A span represents a single operation, also known as a unit of work, from a distributed transaction. It is composed of a name, a start time and other time-related data, structured log data and metadata (also known as span attributes) that can provide additional information to the tracked operation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fexnqoqqlyqwtxotx48py.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fexnqoqqlyqwtxotx48py.png" alt="span" width="670" height="261"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What are Signals?
&lt;/h2&gt;

&lt;p&gt;Signals are outputs from a system that can be used to understand its internal state. Currently, OpenTelemetry supports traces, metrics, logs and baggage (there is an ongoing effort to &lt;a href="https://opentelemetry.io/blog/2024/opentelemetry-announced-support-for-profiling/"&gt;support profiling&lt;/a&gt; as well).&lt;/p&gt;

&lt;h3&gt;
  
  
  Traces
&lt;/h3&gt;

&lt;p&gt;Traces are a way to follow the path of a request through a distributed system. They are composed of spans, which represent the operations that are part of the request.&lt;/p&gt;

&lt;h3&gt;
  
  
  Metrics
&lt;/h3&gt;

&lt;p&gt;Metrics represent a measurement captured at runtime. They are the most important indicators of availability, performance and resource usage of a system. Some important examples of metrics are: throughput, response time, error rate, CPU utilization, Memory utilization, etc.&lt;/p&gt;

&lt;h3&gt;
  
  
  Logs
&lt;/h3&gt;

&lt;p&gt;Maybe this is the most familiar signal for developers. Logs are text records with a timestamp that can be used to understand the behavior of a system. They are useful to understand the context of a specific operation.&lt;/p&gt;

&lt;p&gt;OpenTelemetry uses a different approach to handle this signal. As there are already many logging libraries available, OpenTelemetry acts as a bridge between those logs solutions and the OpenTelemetry ecosystem.&lt;/p&gt;

&lt;h3&gt;
  
  
  Baggage
&lt;/h3&gt;

&lt;p&gt;Baggage is a way to propagate contextual information through the system. It is a key-value pair store that is attached to a span context and must be propagated through the system. The OpenTelemetry official documentation has a &lt;a href="https://opentelemetry.io/docs/concepts/signals/baggage/"&gt;great example&lt;/a&gt; about it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;imagine you want to have a &lt;code&gt;CustomerId&lt;/code&gt; attribute on every span in your trace, which involves multiple services; however, &lt;code&gt;CustomerId&lt;/code&gt; is only available in one specific service. To accomplish your goal, you can use OpenTelemetry Baggage to propagate this value across your system.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Instrumentation
&lt;/h2&gt;

&lt;p&gt;Instrumentation is the process of making your system observable, or making your applications available to emit signals. OpenTelemetry provides two ways to instrument your application: &lt;code&gt;Code-based&lt;/code&gt; and &lt;code&gt;Zero-code&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code-based instrumentation
&lt;/h3&gt;

&lt;p&gt;Code-based instrumentation is the process of adding code to your application to emit signals. In this approach, you must import the OpenTelemetry libraries to your service code. This approach is more flexible because you can customize the instrumentation as you want or use third-party libraries that are only available for code-based instrumentation, besides, your application’s code is not typically instrumented and to instrument it you’ll need to use code-based instrumentation. On the other hand, you are adding some infrastructure responsibilities to your business code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Zero-code instrumentation
&lt;/h3&gt;

&lt;p&gt;Zero-code approach, also known as automatic instrumentation, allows you to add observability to your application without the need to write code. This approach is more straightforward and less error-prone, but it is less flexible than code-based instrumentation. In this approach, the OpenTelemetry capabilities are added to your application as an agent or agent-like installation.&lt;/p&gt;

&lt;p&gt;Maybe you are asking yourself: "How does the zero-code instrumentation work?". The zero-code instrumentation mechanisms may differ by language, ranging from bytecode manipulation, monkey patching, or eBPF to inject calls to the OpenTelemetry API and SDK into your application.  Currently, the automatic instrumentation is available for the following languages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation"&gt;.NET&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/open-telemetry/opentelemetry-java-instrumentation"&gt;Java&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/open-telemetry/opentelemetry-js"&gt;JavaScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/open-telemetry/opentelemetry-php-instrumentation"&gt;PHP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/open-telemetry/opentelemetry-python"&gt;Python&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/open-telemetry/opentelemetry-go-instrumentation"&gt;Go&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;In this article, we covered some important concepts that are essential to understand before diving into the OpenTelemetry world. We talked about observability, context propagation, spans, signals, and instrumentation. In the next articles, we will dive deeper into the OpenTelemetry ecosystem, exploring the OpenTelemetry Collector and the observability data pipeline. If you have any questions or suggestions, please let me know in the comments below.&lt;/p&gt;

</description>
      <category>opentelemetry</category>
      <category>cncf</category>
      <category>observability</category>
    </item>
    <item>
      <title>OpenTelemetry Journey #00 - Introduction to OpenTelemetry</title>
      <dc:creator>Luiz Lelis</dc:creator>
      <pubDate>Sun, 25 Feb 2024 18:00:00 +0000</pubDate>
      <link>https://dev.to/luizhlelis/opentelemetry-journey-00-introduction-to-opentelemetry-32ll</link>
      <guid>https://dev.to/luizhlelis/opentelemetry-journey-00-introduction-to-opentelemetry-32ll</guid>
      <description>&lt;p&gt;The current article is the first from a series of posts about OpenTelemetry. The goal is to provide a comprehensive guide to understand and use OpenTelemetry in your applications.&lt;/p&gt;

&lt;p&gt;First things first, nothing better than using the &lt;a href="https://opentelemetry.io/docs/what-is-opentelemetry/"&gt;definition from the official website&lt;/a&gt; to start this journey:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;OpenTelemetry is an Observability framework and toolkit designed to create and manage telemetry data such as traces, metrics, and logs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It means that the OpenTelemetry project provides not only a &lt;a href="https://github.com/open-telemetry/opentelemetry-specification"&gt;specification&lt;/a&gt; to define the contract between the applications, collectors, and telemetry databases, but also a set of APIs, SDKs, and tools like instrumentation libraries (for different languages), collectors, operators, etc. OpenTelemetry is open-source and vendor-agnostic, so the project is not tied to any specific vendor or cloud provider.&lt;/p&gt;

&lt;p&gt;OpenTelemetry it's a result from the merge of two important projects that are now archived: &lt;a href="https://opentracing.io/"&gt;OpenTracing&lt;/a&gt; and &lt;a href="https://opencensus.io/"&gt;OpenCensus&lt;/a&gt;. The project is incubated in &lt;a href="https://www.cncf.io/projects/"&gt;Cloud Native Computing Foundation (CNCF)&lt;/a&gt; and has a strong community behind it. The CNCF is part of the Linux Foundation and hosts critical components of the global technology infrastructure, including Kubernetes and Prometheus. Currently, OpenTelemetry is the second most active project in terms of contributors in CNCF, only behind Kubernetes. As the project is part of a foundation, it has no commercial interests and is governed by a community of contributors, it means that the project license will not change easily (like happened with important open-source tools like &lt;a href="https://www.elastic.co/blog/doubling-down-on-open"&gt;Elastic&lt;/a&gt;) and the project will not be abandoned by a single company.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why OpenTelemetry?
&lt;/h2&gt;

&lt;p&gt;There are several reasons to use OpenTelemetry in your applications, but I will list some of the most important:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Vendor-agnostic&lt;/strong&gt;: OpenTelemetry is not tied to any specific vendor or cloud provider, so you can use it in any environment, from on-premises to cloud providers;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open-source&lt;/strong&gt;: OpenTelemetry is open-source and has a strong community behind it, so you can trust that the license will not change easily and the project will not be abandoned by a single company;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Standardization&lt;/strong&gt;: OpenTelemetry provides a standard way to collect, process and export telemetry data, so you can use the same instrumentation libraries, collectors, and operators in different environments;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Maybe, you are asking yourself: "But I already had instrumented my applications with vendor-specific libraries and I'm using their agents and monitoring tools, why should I change to OpenTelemetry?". The answer is: maybe you're right and I don't want to encourage you to update the way how you are doing observability in your applications, that's a hard and complex task. But, if you are starting from scratch or you are not happy with your current observability infrastructure, OpenTelemetry is the best choice, independently of the backend telemetry tool that you are using. I would like to invite you to take a look at the number of exporters available in the &lt;a href="https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/exporter"&gt;collector contrib section&lt;/a&gt;, if your backend tracing tool is not there, probably it's already using the &lt;a href="https://github.com/open-telemetry/opentelemetry-proto/blob/main/docs/specification.md"&gt;Open Telemetry Protocol (OTLP)&lt;/a&gt; and you will be able to use the &lt;a href="https://github.com/open-telemetry/opentelemetry-collector/tree/main/exporter/otlpexporter"&gt;core collector&lt;/a&gt;. Otherwise, you should consider changing your backend telemetry tool or contributing to the project creating a new exporter.&lt;/p&gt;

&lt;p&gt;I had mentioned some concepts and terms in this article that I will explain in the next posts, so don't worry if you didn't understand everything. Hope you enjoyed the reading and see you in the next post!&lt;/p&gt;

</description>
      <category>opentelemetry</category>
      <category>cncf</category>
      <category>observability</category>
    </item>
    <item>
      <title>📦 Data consistency, outbox pattern and idempotency in a microservice architecture</title>
      <dc:creator>Luiz Lelis</dc:creator>
      <pubDate>Wed, 19 Oct 2022 01:32:14 +0000</pubDate>
      <link>https://dev.to/luizhlelis/data-consistency-outbox-pattern-and-idempotency-in-a-microservice-architecture-32dl</link>
      <guid>https://dev.to/luizhlelis/data-consistency-outbox-pattern-and-idempotency-in-a-microservice-architecture-32dl</guid>
      <description>&lt;h1&gt;
  
  
  📦 Data consistency, outbox pattern and idempotency in a microservice architecture
&lt;/h1&gt;

&lt;h2&gt;
  
  
  CAP Theorem
&lt;/h2&gt;

&lt;p&gt;Late 90's, the scientist Eric Brewer presented for the first time the CAP Theorem. The theorem states the "two out of three" concept, any distributed system can provide only two of the following guarantees:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Consistency: every request receives the most recent data or an error;&lt;/li&gt;
&lt;li&gt;Availability: every request receives a response, without the guarantee that it contains the most recent data;&lt;/li&gt;
&lt;li&gt;Partition tolerance: the system continues to operate despite an arbitrary number of messages being dropped (or delayed) by the network between nodes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Considering a web app, where there is a network connection between a database and a back-end application, or even between different services in a microservice architecture, the app must be partition tolerant. This means that, even after the network is partitioned, the system still works correctly. Therefore, after a partition, it only remains to decide whether to do one of the following: cancel the operation to ensure the consistency, or proceed with the operation providing availability but risk inconsistency.&lt;/p&gt;

&lt;p&gt;Let me give you an example to clarify the CAP theorem. Imagine an e-commerce that to the process of finishing an order, two services are involved: &lt;code&gt;order&lt;/code&gt; and &lt;code&gt;catalog&lt;/code&gt;. The &lt;code&gt;order&lt;/code&gt; service has to check if there are products available calling the &lt;code&gt;catalog&lt;/code&gt; API before finishing the order. If the &lt;code&gt;catalog&lt;/code&gt; API is not available in that moment for any reason (a partition happened), the &lt;code&gt;catalog&lt;/code&gt; API can behave two different ways:&lt;/p&gt;

&lt;h3&gt;
  
  
  [Consistency] Choose the strong consistency returning an error
&lt;/h3&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%2Fraw.githubusercontent.com%2Fluizhlelis%2Fcap-playground%2Fmain%2Fassets%2Fconsistent-system.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%2Fraw.githubusercontent.com%2Fluizhlelis%2Fcap-playground%2Fmain%2Fassets%2Fconsistent-system.png" alt="consistent-system"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  [Availability] Giving up the strong consistency returning to the client that eventually the request will be processed
&lt;/h3&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%2Fraw.githubusercontent.com%2Fluizhlelis%2Fcap-playground%2Fmain%2Fassets%2Favailable-system.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%2Fraw.githubusercontent.com%2Fluizhlelis%2Fcap-playground%2Fmain%2Fassets%2Favailable-system.png" alt="available-system"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The pattern that will be discussed in this article is an eventual consistency pattern. So, the outbox pattern gives up the solid consistency for focus on availability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Outbox pattern
&lt;/h2&gt;

&lt;p&gt;The outbox pattern makes sense only for distributed systems, discussing it in a monolithic scenario is completely nonsense. The problem that this pattern solves is: how to reliably/atomically update the database and send messages/events?&lt;/p&gt;

&lt;p&gt;The way as the pattern solves this problem is relatively easy to understand, basically it can be described in four steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A service that persists data in a database, inserts also messages/events into a table (which is called outbox table) as part of the local transaction;&lt;/li&gt;
&lt;li&gt;The service appends the messages/events to an attribute of the record being updated;&lt;/li&gt;
&lt;li&gt;Another process, called &lt;code&gt;Message Relay&lt;/code&gt;, publishes the events inserted into the database to a message broker;&lt;/li&gt;
&lt;li&gt;If something wrong happen, the &lt;code&gt;Message Relay&lt;/code&gt; process retry to send the event a few times until the set limit been reached;&lt;/li&gt;
&lt;li&gt;The messages/events are stored in the consumer side too.&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%2Fraw.githubusercontent.com%2Fluizhlelis%2Fcap-playground%2Fmain%2Fassets%2Foutbox-pattern.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%2Fraw.githubusercontent.com%2Fluizhlelis%2Fcap-playground%2Fmain%2Fassets%2Foutbox-pattern.png" alt="outbox-pattern"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Edited version from:&lt;/strong&gt; &lt;a href="https://github.com/dotnetcore/CAP" rel="noopener noreferrer"&gt;https://github.com/dotnetcore/CAP&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So the outbox pattern would guarantee data consistency between the services, but what if the events are consumed twice? This is where idempotency comes in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Idempotency
&lt;/h2&gt;

&lt;p&gt;In a scenario with a broker &lt;code&gt;at least once delivery&lt;/code&gt; the message could be persisted more than one time in two different situations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The producer had produced a message and sent it to the broker, the consumer stores the data in the database but don't return an &lt;code&gt;ack&lt;/code&gt; in a timely manner. Then, the broker concludes that the message was not processed sending the message again;&lt;/li&gt;
&lt;li&gt;In the outbox scenario, the producer had stored the message in the &lt;code&gt;outbox table&lt;/code&gt; for the first time and sent it to the broker, but for some reason it wasn't able to update the &lt;code&gt;outbox table&lt;/code&gt; saying that the message was published. For that reason, it will keep sending the message again until the &lt;code&gt;outbox table&lt;/code&gt; had been updated.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: that could be even worse in a multiprocessing scenario&lt;/p&gt;
&lt;/blockquote&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%2Fraw.githubusercontent.com%2Fluizhlelis%2Fcap-playground%2Fmain%2Fassets%2Fidempotency.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%2Fraw.githubusercontent.com%2Fluizhlelis%2Fcap-playground%2Fmain%2Fassets%2Fidempotency.png" alt="idempotency"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To turn your consumer in an idempotent one, you could register in the database the message/event ID that has been rightly processed. When the consumer is processing a new message, it would be able detect and discard duplicates.&lt;/p&gt;

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

&lt;p&gt;The outbox pattern is an eventual consistency pattern that cares about the system's availability but is not a silver bullet. When using it you should be careful about double message consumption choosing an idempotent consumer approach for example.&lt;/p&gt;

&lt;p&gt;There are many libraries in &lt;code&gt;.NET&lt;/code&gt; that helps you implementing the &lt;code&gt;outbox pattern&lt;/code&gt; like: &lt;a href="https://github.com/MassTransit/MassTransit" rel="noopener noreferrer"&gt;MassTransit&lt;/a&gt;, &lt;a href="https://github.com/Particular/NServiceBus" rel="noopener noreferrer"&gt;NServiceBus&lt;/a&gt;, &lt;a href="https://github.com/dotnetcore/CAP" rel="noopener noreferrer"&gt;CAP&lt;/a&gt;. Talking about idempotency, a special mention to a specific lib from a big friend that runs on top of &lt;code&gt;CAP&lt;/code&gt; which is called &lt;a href="https://github.com/rafaelpadovezi/Ziggurat" rel="noopener noreferrer"&gt;Ziggurat&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you got until here and liked the article content, let me know reacting to the current post. You can also open a discussion below, I'll try to answer ASAP. Next article, I'll show you the code specifying all you need to build a system using &lt;code&gt;outbox pattern&lt;/code&gt; and &lt;code&gt;idempotency&lt;/code&gt; using &lt;code&gt;.NET&lt;/code&gt;, &lt;code&gt;CAP&lt;/code&gt; and &lt;code&gt;Ziggurat&lt;/code&gt;. Hope you like it!&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/luizhlelis/cap-playground" rel="noopener noreferrer"&gt;CAP Playground, 📤 Just playing a bit with CAP and outbox pattern&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[PT-BR]&lt;/strong&gt; JS+, Data consistency, outbox pattern and idempotency in a microservice architecture with .NET; &lt;a href="https://www.youtube.com/watch?v=rqade8-xjyc" rel="noopener noreferrer"&gt;JS+ TechTalks #22 - Edição Lisboa&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Richardson, Chris; &lt;a href="https://microservices.io/patterns/communication-style/idempotent-consumer.html" rel="noopener noreferrer"&gt;Pattern: Idempotent Consumer&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Richardson, Chris; &lt;a href="https://microservices.io/patterns/data/transactional-outbox.html" rel="noopener noreferrer"&gt;Pattern: Transactional outbox&lt;/a&gt;&lt;/p&gt;

</description>
      <category>outboxpattern</category>
      <category>microservices</category>
    </item>
    <item>
      <title>🔐 Building a self signed server in golang</title>
      <dc:creator>Luiz Lelis</dc:creator>
      <pubDate>Mon, 07 Feb 2022 03:50:27 +0000</pubDate>
      <link>https://dev.to/luizhlelis/building-a-self-signed-server-in-golang-565i</link>
      <guid>https://dev.to/luizhlelis/building-a-self-signed-server-in-golang-565i</guid>
      <description>&lt;p&gt;This article will be useful to you if you want to create a self signed server in &lt;code&gt;golang&lt;/code&gt;. There are many ways to use certificates to build and run a &lt;code&gt;https&lt;/code&gt; server, this article will approach one of them: &lt;code&gt;self-signed&lt;/code&gt; using openssl tool. You can see all the source code used in the current article in the public &lt;a href="https://github.com/luizhlelis/go-lang-https-self-signed" rel="noopener noreferrer"&gt;github repository&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why https?
&lt;/h2&gt;

&lt;p&gt;Firstly let's remember some concepts. The Hypertext Transfer Protocol (&lt;a href="https://tools.ietf.org/html/rfc2616" rel="noopener noreferrer"&gt;Http&lt;/a&gt;) specifies a standard track protocol for the internet community and has been in use since 1990. The problem with the use of only http is that the exchanged messages between server and client will not be encrypted, so everyone who intercepts those messages will know exactly what that messages means and also can modify the data to masquerade as one of the peers involved. To avoid attacks like &lt;a href="https://tools.ietf.org/html/rfc4949" rel="noopener noreferrer"&gt;man-in-the-middle&lt;/a&gt; and to provide private communication, the Secure Sockets Layer (&lt;a href="https://tools.ietf.org/html/rfc6101" rel="noopener noreferrer"&gt;SSL&lt;/a&gt;) was first introduced by Netscape in 1994 being the pioneer in secure communications protocols, but it was succeeded later by the Transport Layer Security (&lt;a href="https://tools.ietf.org/html/rfc8446" rel="noopener noreferrer"&gt;TLS&lt;/a&gt;). TLS is the channel-oriented security protocol currently in use on the internet and it's composed basically by two protocols: the handshake and the record protocol.&lt;/p&gt;

&lt;p&gt;The TLS Handshake protocol is responsible to authenticate two end-points, besides that, it also negotiates cryptographic parameters and generates keying material. The record protocol uses the parameters established by the handshake protocol to protect traffic between the end-points.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why self signed?
&lt;/h2&gt;

&lt;p&gt;By default your operation system trusts in a set of certification authorities (CA) like GlobalSign, Let's Encrypt, Digicert, GoDaddy, etc. The self-signed certificates are those that aren't signed by any CA, in this case, the certificate is signed with its own private key, instead of requesting it from a CA. So in that case, the client should trust in the certificate issued by the server.&lt;/p&gt;

&lt;p&gt;The first thing you need to ask yourself is: why do I need a self signed certificate? There are few reasons for that and I've never faced a reason to use it in a production environment. So maybe you're thinking: so on, what is this article for? There are some scenarios which demands you to provide a &lt;code&gt;https&lt;/code&gt; endpoint (to run your application locally for example). In my case, I needed it to run an application locally to integrate it with a cloud service that requires a &lt;code&gt;https&lt;/code&gt; endpoint. There are some frameworks, SDKs or tool kits written in other languages that provides to you an &lt;code&gt;https&lt;/code&gt; endpoint natively with self-signed certificates (it's the case of &lt;a href="https://www.oracle.com/java/technologies/downloads/" rel="noopener noreferrer"&gt;JDK&lt;/a&gt; and &lt;a href="https://dotnet.microsoft.com/en-us/download" rel="noopener noreferrer"&gt;.NET Core&lt;/a&gt;), but I didn't find anything like that in &lt;code&gt;golang&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; if you're gonna use &lt;code&gt;https&lt;/code&gt; in production, I strongly recommend you to use a certificate signed by a CA (try to use a cloud solution like &lt;a href="https://aws.amazon.com/pt/certificate-manager/" rel="noopener noreferrer"&gt;AWS Certificate Manager&lt;/a&gt;, or an open source tool like &lt;a href="https://certbot.eff.org/" rel="noopener noreferrer"&gt;certbot&lt;/a&gt;). There are some security risks that you should be aware of when using self-signed, you can see more about it &lt;a href="https://www.keyfactor.com/blog/self-signed-certificate-risks/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Running the project
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;"Talk is cheap, show me the code" - Linus Torvalds&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To proceed with the next steps, you're gonna need to clone &lt;a href="https://github.com/luizhlelis/go-lang-https-self-signed" rel="noopener noreferrer"&gt;this github repo&lt;/a&gt;. The current example is composed by a server and a client called &lt;code&gt;https-server&lt;/code&gt; and &lt;code&gt;https-client&lt;/code&gt; respectively. Each one runs in its specific container, the server provides a REST API written in golang and is responsible to create the self signed certificate. That certificate protects two hostnames: &lt;code&gt;localhost&lt;/code&gt; and &lt;code&gt;https-server&lt;/code&gt;, that multi-domain approach is possible thanks to the &lt;a href="https://www.digicert.com/faq/subject-alternative-name.htm" rel="noopener noreferrer"&gt;Subject Alternative Names&lt;/a&gt; (SANs). Take a look at the diagram below that represents the current example:&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%2Fraw.githubusercontent.com%2Fluizhlelis%2Fgo-lang-https-self-signed%2Fmain%2Fdocs%2Fcert-diagram.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%2Fraw.githubusercontent.com%2Fluizhlelis%2Fgo-lang-https-self-signed%2Fmain%2Fdocs%2Fcert-diagram.png" alt="certificate-diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see above, the server generates the certificate and the clients trust that certificate (client container or a client running in the host). So, to up the client and server containers, run the command below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Server
&lt;/h2&gt;

&lt;p&gt;The command above will firstly up the server container and run some commands from a file called &lt;a href="https://github.com/luizhlelis/go-lang-https-self-signed/blob/main/server/scripts/generate-certificate.sh" rel="noopener noreferrer"&gt;generate-certificate.sh&lt;/a&gt;. That bash file contains some &lt;a href="https://www.openssl.org/" rel="noopener noreferrer"&gt;openssl&lt;/a&gt; commands to create the self signed certificate. First, it generates a &lt;code&gt;servercert.key&lt;/code&gt; and &lt;code&gt;servercert.csr&lt;/code&gt; which are respectively: the private key and the certificate signing request (CSR) that contains the public key. The &lt;code&gt;CN&lt;/code&gt; field in &lt;code&gt;-subj&lt;/code&gt; is very important because some browsers like chrome require that information (&lt;code&gt;CN&lt;/code&gt; means Common Name, that's the domain name you would like to have SSL secured). Then, the certificate file will be generated also, this file, named &lt;code&gt;servercert.crt&lt;/code&gt;, is generated by the last command in the bash file. That's the self-signed certificate signed by your own &lt;code&gt;servercert.key&lt;/code&gt; private key. The &lt;code&gt;x509&lt;/code&gt; flag states the standard format of an SSL/TLS certificate, the &lt;code&gt;X.509&lt;/code&gt; format. Finally, the &lt;code&gt;https&lt;/code&gt; server are gonna get up by the &lt;code&gt;go run main.go&lt;/code&gt; command. Take a look at the bash commands bellow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apk update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apk add openssl &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /var/cache/apk/&lt;span class="k"&gt;*&lt;/span&gt;
openssl req &lt;span class="nt"&gt;-new&lt;/span&gt; &lt;span class="nt"&gt;-subj&lt;/span&gt; &lt;span class="s2"&gt;"/C=US/ST=California/CN=localhost"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-newkey&lt;/span&gt; rsa:2048 &lt;span class="nt"&gt;-nodes&lt;/span&gt; &lt;span class="nt"&gt;-keyout&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$FILE_CERT_NAME&lt;/span&gt;&lt;span class="s2"&gt;.key"&lt;/span&gt; &lt;span class="nt"&gt;-out&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$FILE_CERT_NAME&lt;/span&gt;&lt;span class="s2"&gt;.csr"&lt;/span&gt;
openssl x509 &lt;span class="nt"&gt;-req&lt;/span&gt; &lt;span class="nt"&gt;-days&lt;/span&gt; 365 &lt;span class="nt"&gt;-in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$FILE_CERT_NAME&lt;/span&gt;&lt;span class="s2"&gt;.csr"&lt;/span&gt; &lt;span class="nt"&gt;-signkey&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$FILE_CERT_NAME&lt;/span&gt;&lt;span class="s2"&gt;.key"&lt;/span&gt; &lt;span class="nt"&gt;-out&lt;/span&gt; &lt;span class="s2"&gt;"certificates/&lt;/span&gt;&lt;span class="nv"&gt;$FILE_CERT_NAME&lt;/span&gt;&lt;span class="s2"&gt;.crt"&lt;/span&gt; &lt;span class="nt"&gt;-extfile&lt;/span&gt; &lt;span class="s2"&gt;"self-signed-cert.ext"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the &lt;code&gt;ext&lt;/code&gt; file has all tha SANs protected by the certificate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;subjectAltName = @alt_names
[alt_names]
DNS.1 = localhost
DNS.2 = https-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that you already have the certificate, you need to serve your https server. Inside the &lt;code&gt;main.go&lt;/code&gt; file, the &lt;code&gt;ListenAndServeTLS&lt;/code&gt; method is responsible for use the cert and key to serve the &lt;code&gt;https&lt;/code&gt; self signed server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;handleRequests&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="n"&gt;tlsCert&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"tls-certificate"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;tlsKey&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"tls-key"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;serverPort&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"server-port"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="n"&gt;router&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewRouter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StrictSlash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;controllers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleHomeRoutes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;router&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"https"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServeTLS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serverPort&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tlsCert&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tlsKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;router&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Along with that, as the cert and key was gotten from the &lt;code&gt;.env&lt;/code&gt; file, you should declare both paths:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tls-certificate="certificates/servercert.crt"
tls-key="servercert.key"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;The client container has a volume with the path where the server certificate was generated: &lt;code&gt;./server/certificates:/certificates&lt;/code&gt;. That's because the client needs to trust that certificate to make &lt;code&gt;https&lt;/code&gt; calls to the server. The command &lt;code&gt;update-ca-certificates&lt;/code&gt; is responsible to add that certificate to the system's trust store, it was executed in &lt;a href="https://github.com/luizhlelis/go-lang-https-self-signed/blob/main/client/scripts/trust-server-certificate.sh#L11" rel="noopener noreferrer"&gt;trust-server-certificate.sh&lt;/a&gt; bash file. After that, the client will be able to call the server with https (the handshake will happen normally). The &lt;code&gt;https-client&lt;/code&gt; container calls the &lt;code&gt;/home&lt;/code&gt; endpoint from the server with https two times after trusting its certificate, take a look at the &lt;code&gt;curl&lt;/code&gt; calls in &lt;a href="https://github.com/luizhlelis/go-lang-https-self-signed/blob/main/client/get-server-home.sh" rel="noopener noreferrer"&gt;get-server-home.sh&lt;/a&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/ash&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Installing curl package"&lt;/span&gt;
apk update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apk add curl &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /var/cache/apk/&lt;span class="k"&gt;*&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Two requests below to get https server home"&lt;/span&gt;
&lt;span class="nb"&gt;sleep &lt;/span&gt;10
curl https://https-server:8081/home
&lt;span class="nb"&gt;sleep &lt;/span&gt;20
curl https://https-server:8081/home
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Call the server with a client running locally (localhost)
&lt;/h2&gt;

&lt;p&gt;As mentioned before, you need to trust the server certificate in your local trust store if you want to use https. If you're using a linux based OS, you should run the commands shown in &lt;code&gt;trust-server-certificate.sh&lt;/code&gt; file. Otherwise, follow one of the steps below:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://tosbourn.com/getting-os-x-to-trust-self-signed-ssl-certificates/" rel="noopener noreferrer"&gt;Mac Os&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://superuser.com/questions/370217/trust-ssl-certificate-to-local-system-account" rel="noopener noreferrer"&gt;Windows&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://unix.stackexchange.com/questions/90450/adding-a-self-signed-certificate-to-the-trusted-list" rel="noopener noreferrer"&gt;Linux&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you call a server endpoint before trusting the server certificate, you'll get an error like the following in your browser:&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%2Fraw.githubusercontent.com%2Fluizhlelis%2Fgo-lang-https-self-signed%2Fmain%2Fdocs%2Fbefore-trust.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%2Fraw.githubusercontent.com%2Fluizhlelis%2Fgo-lang-https-self-signed%2Fmain%2Fdocs%2Fbefore-trust.png" alt="before-trust"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;after trusting the certificate locally, you'll get the response with a 200 Ok status code:&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%2Fraw.githubusercontent.com%2Fluizhlelis%2Fgo-lang-https-self-signed%2Fmain%2Fdocs%2Fafter-trust.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%2Fraw.githubusercontent.com%2Fluizhlelis%2Fgo-lang-https-self-signed%2Fmain%2Fdocs%2Fafter-trust.png" alt="after-trust"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;if you expand the certificate, you will see all the domains secured by the self-signed certificate:&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%2Fraw.githubusercontent.com%2Fluizhlelis%2Fgo-lang-https-self-signed%2Fmain%2Fdocs%2Fcertificate-sans.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%2Fraw.githubusercontent.com%2Fluizhlelis%2Fgo-lang-https-self-signed%2Fmain%2Fdocs%2Fcertificate-sans.png" alt="certificate-sans"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;that behavior is also shown in the server stdout, before trusting the certificate there is a handshake error, but after trusting it, the handshake is successful:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;https-server | 2022/02/07 00:59:53 http: TLS handshake error from 172.19.0.1:55672: remote error: tls: unknown certificate
https-server | Home page endepoint hit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;Digicert; &lt;a href="https://www.digicert.com/faq/subject-alternative-name.htm" rel="noopener noreferrer"&gt;Multi-Domain (SAN) Certificates - Using Subject Alternative Names&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Globalsign; &lt;a href="https://www.globalsign.com/en/ssl-information-center/dangers-self-signed-certificates" rel="noopener noreferrer"&gt;The Dangers of Self-Signed SSL Certificates&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Keyfactor; &lt;a href="https://www.globalsign.com/pt-br/ssl-information-center/what-are-certification-authorities-trust-hierarchies" rel="noopener noreferrer"&gt;What is a Self-Signed Certificate? Advantages, Risks &amp;amp; Alternatives&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;OpenSSL; &lt;a href="https://www.openssl.org/" rel="noopener noreferrer"&gt;Cryptography and SSL/TLS Toolkit&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;RFC 2616; &lt;a href="https://tools.ietf.org/html/rfc2616" rel="noopener noreferrer"&gt;Hypertext Transfer Protocol -- HTTP/1.1&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;RFC 4949; &lt;a href="https://datatracker.ietf.org/doc/html/rfc4949" rel="noopener noreferrer"&gt;Internet Security Glossary, Version 2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;RFC 6101; &lt;a href="https://tools.ietf.org/html/rfc6101" rel="noopener noreferrer"&gt;The Secure Sockets Layer (SSL) Protocol Version 3.0&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;RFC 8446; &lt;a href="https://datatracker.ietf.org/doc/html/rfc8446" rel="noopener noreferrer"&gt;The Transport Layer Security (TLS) Protocol Version 1.3&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>https</category>
      <category>tls</category>
      <category>ssl</category>
    </item>
    <item>
      <title>⚡ 🔍 Typesense search engine: an easier-to-use alternative to ElasticSearch</title>
      <dc:creator>Luiz Lelis</dc:creator>
      <pubDate>Fri, 15 Oct 2021 22:41:10 +0000</pubDate>
      <link>https://dev.to/luizhlelis/typesense-search-engine-an-easier-to-use-alternative-to-elasticsearch-33dg</link>
      <guid>https://dev.to/luizhlelis/typesense-search-engine-an-easier-to-use-alternative-to-elasticsearch-33dg</guid>
      <description>&lt;p&gt;In a daily development process, it's common the need to search a specific term in a large amount of data. The search engine tools came to solve this kind of problem and one of the most famous is called &lt;a href="https://github.com/elastic/elasticsearch"&gt;ElasticSearch&lt;/a&gt;. If you have already worked with ElasticSearch you probably know that it's such a powerful tool, but it's also complex and has a steep learning curve. For example, doing an in-house deployment of ElasticSearch you will face a high production ops overhead dealing with over 3000 configuration parameters.&lt;/p&gt;

&lt;p&gt;Built in C++, &lt;a href="https://github.com/typesense/typesense"&gt;Typesense&lt;/a&gt; is an easier-to-use alternative to ElasticSearch. The community describes it as an open-source, fast, typo tolerant, and easy-to-use search engine. The current article is a quick introduction to &lt;code&gt;Typesense&lt;/code&gt; using a search engine example for the &lt;code&gt;Nobel Prize Winners&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Server configuration
&lt;/h2&gt;

&lt;p&gt;Just like most search engine tools, &lt;code&gt;Typesense&lt;/code&gt; is a NoSql document-oriented database. For the current example, I'll self-host &lt;code&gt;Typesense&lt;/code&gt; on my local machine using the official &lt;a href="https://hub.docker.com/r/typesense/typesense/"&gt;docker image&lt;/a&gt;, as you can see in the example &lt;a href="https://github.com/luizhlelis/typesense-playground"&gt;source code&lt;/a&gt;. There are &lt;a href="https://typesense.org/docs/0.21.0/api/server-configuration.html#using-command-line-arguments"&gt;few parameters&lt;/a&gt; to configure the &lt;code&gt;Typesense&lt;/code&gt; server, but you could let the default values and just configure the &lt;code&gt;--api-key&lt;/code&gt; (admin API key that allows all operations) and the &lt;code&gt;--data-dir&lt;/code&gt; (path to the directory where data will be stored on disk) parameters. Take a look at the &lt;code&gt;typesense&lt;/code&gt; service on &lt;code&gt;docker-compose&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="na"&gt;typesense&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;typesense/typesense:0.22.0.rcs11&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;typesense&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;TYPESENSE_API_KEY=Hu52dwsas2AdxdE&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;TYPESENSE_DATA_DIR=/typesense-data&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;./typesense-data:/typesense-data/"&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8108:8108"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: when using &lt;code&gt;environment variables&lt;/code&gt;, you need to add the &lt;code&gt;TYPESENSE_&lt;/code&gt; prefix to the variable name&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;One important thing to note is: I choose to create a volume for the &lt;code&gt;typesense-data&lt;/code&gt; folder, so the data stored in the container will be persisted locally. Along with the &lt;code&gt;typesense&lt;/code&gt; service, I registered a &lt;code&gt;seed-data&lt;/code&gt; service on &lt;code&gt;docker-compose.yml&lt;/code&gt; to seed the &lt;code&gt;Nobel Prize Winners&lt;/code&gt; data in the &lt;code&gt;Typesense&lt;/code&gt; server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="na"&gt;seed-data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
      &lt;span class="na"&gt;dockerfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Dockerfile&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;seed-data&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;typesense&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;TYPESENSE_API_KEY=Hu52dwsas2AdxdE&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SERVER_HOSTNAME=typesense&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;./scripts:/app/"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;./seed-data:/seed-data/"&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;[&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/app/wait-for-it.sh"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;typesense:8108"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-s"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-t"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;40"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/app/batch-import-docs.sh"&lt;/span&gt;
      &lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The volumes listed above are: a path to the scripts (&lt;a href="https://github.com/luizhlelis/typesense-playground/blob/main/src/scripts/wait-for-it.sh"&gt;wait-for-it.sh&lt;/a&gt; that waits for &lt;code&gt;typesense&lt;/code&gt; to respond on it's &lt;code&gt;port&lt;/code&gt; and &lt;a href="https://github.com/luizhlelis/typesense-playground/blob/main/src/scripts/batch-import-docs.sh"&gt;batch-import-docs.sh&lt;/a&gt; which seed the data) and also a path to the dataset formatted as &lt;a href="https://jsonlines.org/"&gt;JSONLines&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create collection and import documents
&lt;/h2&gt;

&lt;p&gt;Before starting to import the documents, it's important to create a &lt;code&gt;collection&lt;/code&gt;. In &lt;code&gt;Typesense&lt;/code&gt;, a group of related documents is called &lt;code&gt;collection&lt;/code&gt; and &lt;code&gt;schema&lt;/code&gt; is the name of the fields from the documents added in a &lt;code&gt;collection&lt;/code&gt;. It might help to think of a &lt;code&gt;schema&lt;/code&gt; as the "types" in a strongly-typed programming language. The most important thing that you should keep in mind is: all fields that you mention in a &lt;code&gt;collection&lt;/code&gt;'s &lt;code&gt;schema&lt;/code&gt; will be indexed in memory. Take a look at the &lt;code&gt;prizes&lt;/code&gt; collection created for the current example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s2"&gt;"http://&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SERVER_HOSTNAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:8108/collections"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
       &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="se"&gt;\&lt;/span&gt;
       &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
       &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-TYPESENSE-API-KEY: &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TYPESENSE_API_KEY&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
       &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
         "name": "prizes",
         "default_sorting_field": "year",
         "fields": [
           {"name": "id", "type": "string" },
           {"name": "year", "type": "int64" },
           {"name": "category", "type": "string", "facet": true },
           {"name": "laureates_full_name", "type": "string[]" }
         ],
         "default_sorting_field": "year"
       }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: indexes are gonna improve the execution of queries in terms of performance. If an appropriate index exists for a query, &lt;code&gt;Typesense&lt;/code&gt; will use it to limit the number of documents to inspect&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;code&gt;schema&lt;/code&gt; above has four indexed fields: &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;year&lt;/code&gt;, &lt;code&gt;category&lt;/code&gt; and &lt;code&gt;laureates_full_name&lt;/code&gt;, but if you look at the &lt;a href="https://github.com/luizhlelis/typesense-playground/blob/main/src/seed-data/documents.jsonl"&gt;dataset to be imported&lt;/a&gt;, you'll notice some extra fields, for example: &lt;code&gt;laureates.motivation&lt;/code&gt;, &lt;code&gt;laureates.share&lt;/code&gt;, &lt;code&gt;laureates.surname&lt;/code&gt;. Those fields will be stored on disk, but will not take up any memory.&lt;/p&gt;

&lt;p&gt;For the dataset import, I'm using the &lt;a href="https://typesense.org/docs/0.21.0/api/documents.html#import-documents"&gt;import API&lt;/a&gt; to index multiple documents in a batch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-TYPESENSE-API-KEY: &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TYPESENSE_API_KEY&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="nt"&gt;--data-binary&lt;/span&gt; @../seed-data/documents.jsonl &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;"http://&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SERVER_HOSTNAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:8108/collections/prizes/documents/import?action=create"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that all the steps are clear, just type the command below to up the &lt;code&gt;typesense&lt;/code&gt; server and also seed the data inside it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose up &lt;span class="nt"&gt;--build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Searching for the Nobel Prize Winners
&lt;/h1&gt;

&lt;p&gt;Now that the &lt;code&gt;typesense&lt;/code&gt; server is up and running, let's start searching for the Nobel Prize winners. First, export the environment variable &lt;code&gt;TYPESENSE_API_KEY&lt;/code&gt; to use it locally as a typesense client:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;TYPESENSE_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Hu52dwsas2AdxdE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, use the &lt;a href="https://typesense.org/docs/0.21.0/api/documents.html#search"&gt;search API&lt;/a&gt; to search for documents. For example, imagine that you want to search for the Marie Curie prize, type the command below locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-TYPESENSE-API-KEY: &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TYPESENSE_API_KEY&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;"http://localhost:8108/collections/prizes/documents/search&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
?q=Curii&amp;amp;query_by=laureates_full_name&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
&amp;amp;sort_by=year:desc"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Did you notice the typo in the query text? Instead of &lt;code&gt;Curie&lt;/code&gt;, &lt;code&gt;Curii&lt;/code&gt; was sent in the query. No big deal, &lt;code&gt;Typesense&lt;/code&gt; handles typographic errors, take a look at the documents returned (the response body has been cut for didactic purposes only):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"facet_counts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"found"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hits"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"document"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"chemistry"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"55"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"laureates"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"firstname"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Marie"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"6"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"motivation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;in recognition of her services to the advancement of chemistry by the discovery of the elements radium and polonium, by the isolation of radium and the study of the nature and compounds of this remarkable element&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"share"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"surname"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Curie"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"laureates_full_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="s2"&gt;"Marie Curie"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"year"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1911&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"document"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"physics"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"12"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"laureates"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"firstname"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Henri"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"motivation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;in recognition of the extraordinary services he has rendered by his discovery of spontaneous radioactivity&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"share"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"surname"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Becquerel"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"firstname"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Pierre"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"motivation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;in recognition of the extraordinary services they have rendered by their joint researches on the radiation phenomena discovered by Professor Henri Becquerel&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"share"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"surname"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Curie"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"firstname"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Marie"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"6"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"motivation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;in recognition of the extraordinary services they have rendered by their joint researches on the radiation phenomena discovered by Professor Henri Becquerel&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"share"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"surname"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Curie"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"laureates_full_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="s2"&gt;"Henri Becquerel"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="s2"&gt;"Pierre Curie"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="s2"&gt;"Marie Curie"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"year"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1903&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;&lt;code&gt;Typesense&lt;/code&gt; has been turning into a nice alternative to search engines like Algolia and ElasticSearch. Its simple server setup and intuitive API turns the navigation much easier. For the current example, I used CURL to interact with &lt;code&gt;Typesense&lt;/code&gt; Server directly, but there are many &lt;a href="https://github.com/typesense/typesense#api-clients"&gt;clients and integrations&lt;/a&gt; developed in your favorite language.&lt;/p&gt;

&lt;p&gt;Now, I want to know your opinion, if you're using &lt;code&gt;Typesense&lt;/code&gt; in production &lt;a href="https://github.com/typesense/typesense/issues/140"&gt;let the community knows&lt;/a&gt;! If you got here and liked the article content, let me know by reacting to the current post. You can also open a discussion below, I'll try to answer it soon. On the other hand, if you think that I said something wrong, please open an issue in the &lt;a href="https://github.com/luizhlelis/typesense-playground"&gt;article's github repo&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>typesense</category>
      <category>search</category>
      <category>fuzzy</category>
      <category>cpp</category>
    </item>
    <item>
      <title>.NET Core 2.1 container images were deleted from Docker Hub!</title>
      <dc:creator>Luiz Lelis</dc:creator>
      <pubDate>Sat, 28 Aug 2021 16:03:20 +0000</pubDate>
      <link>https://dev.to/luizhlelis/net-core-2-1-container-images-were-deleted-from-docker-hub-3nhm</link>
      <guid>https://dev.to/luizhlelis/net-core-2-1-container-images-were-deleted-from-docker-hub-3nhm</guid>
      <description>&lt;p&gt;If you started receiving errors when pulling old versions of dotnet docker images (like the &lt;code&gt;.NET 2.1&lt;/code&gt;), it's because Microsoft deleted them from Docker Hub on August 21st, 2021. That date is not a coincidence, the &lt;code&gt;.NET Core 2.1&lt;/code&gt; reached end of support in the same date. For more details take a look at the official &lt;a href="https://github.com/dotnet/announcements/issues/197"&gt;dotnet announcement&lt;/a&gt; or also the &lt;a href="https://devblogs.microsoft.com/dotnet/net-core-2-1-container-images-will-be-deleted-from-docker-hub/"&gt;dotnet blog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In my case, the error below was thrown when pulling the &lt;code&gt;microsoft/dotnet:2.2-aspnetcore-runtime&lt;/code&gt; image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Error response from daemon: pull access denied &lt;span class="k"&gt;for
&lt;/span&gt;microsoft/dotnet, repository does not exist or may
require &lt;span class="s1"&gt;'docker login'&lt;/span&gt;: denied: requested access to
the resource is denied
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As mentioned before, the reason was: microsoft moved the &lt;code&gt;out of support&lt;/code&gt; images from docker hub to &lt;a href="https://github.com/microsoft/containerregistry"&gt;microsoft container registry&lt;/a&gt; (MCR). To solve that problem, I updated the image to &lt;code&gt;mcr.microsoft.com/dotnet/core/runtime:2.2&lt;/code&gt;. So, instead of pulling images from docker hub (&lt;code&gt;microsoft/dotnet&lt;/code&gt;) you should pull them from MCR (&lt;code&gt;mcr.microsoft.com&lt;/code&gt;), just like described below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;microsoft/dotnet:2.1-sdk -&amp;gt; mcr.microsoft.com/dotnet/sdk:2.1
microsoft/dotnet:2.1-aspnetcore-runtime -&amp;gt; mcr.microsoft.com/dotnet/aspnet:2.1
microsoft/dotnet:2.1-runtime -&amp;gt; mcr.microsoft.com/dotnet/runtime:2.1
microsoft/dotnet:2.1-runtime-deps -&amp;gt; mcr.microsoft.com/dotnet/runtime-deps:2.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: see the full list of &lt;code&gt;from docker hub to MCR images&lt;/code&gt; &lt;a href="https://devblogs.microsoft.com/dotnet/net-core-2-1-container-images-will-be-deleted-from-docker-hub/#pulling-images-from-mcr"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Maybe you're asking yourself: why microsoft announced that they removed the 2.1 images from docker hub but not the 2.2 images? The response is simple: &lt;code&gt;.NET 2.2&lt;/code&gt; was deprecated in December 23, 2019, so microsoft don't need to announce as they are not supporting it anymore 🤷‍♂️&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: it's strongly recommended move to later &lt;code&gt;.NET&lt;/code&gt; versions instead of using &lt;code&gt;out of support&lt;/code&gt; versions like 2.1 or 2.2&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>docker</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>[c#] Using W3C Trace Context standard in distributed tracing</title>
      <dc:creator>Luiz Lelis</dc:creator>
      <pubDate>Mon, 14 Jun 2021 03:06:07 +0000</pubDate>
      <link>https://dev.to/luizhlelis/c-using-w3c-trace-context-standard-in-distributed-tracing-1nm0</link>
      <guid>https://dev.to/luizhlelis/c-using-w3c-trace-context-standard-in-distributed-tracing-1nm0</guid>
      <description>&lt;h1&gt;
  
  
  [c#] Using W3C Trace Context standard in distributed tracing
&lt;/h1&gt;

&lt;p&gt;In my last &lt;a href="https://dev.to/luizhlelis/using-w3c-trace-context-standard-in-distributed-tracing-3743"&gt;article&lt;/a&gt;, I wrote about the W3C trace context standard and what kind of problem it came to solve. The current article purpose is to show the trace context usage in a microservice architecture. For the first practical example, I chose to develop all applications using c# with &lt;code&gt;.NET 5&lt;/code&gt; (&lt;a href="https://docs.microsoft.com/aspnet/core/tutorials/first-web-api?view=aspnetcore-5.0&amp;amp;tabs=visual-studio" rel="noopener noreferrer"&gt;sample WeatherForecast web API&lt;/a&gt;) and run all of them locally via docker-compose. Hope you enjoy it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Application architecture
&lt;/h2&gt;

&lt;p&gt;The main objective is to propagate a message with &lt;code&gt;traceparent&lt;/code&gt; id throw two APIs and one worker using &lt;a href="https://www.w3.org/TR/trace-context" rel="noopener noreferrer"&gt;W3C trace context&lt;/a&gt; standard. The &lt;code&gt;first-api&lt;/code&gt; calls the &lt;code&gt;second-api&lt;/code&gt; by a http call while the &lt;code&gt;second-api&lt;/code&gt; has an asynchronous communication with the &lt;code&gt;worker&lt;/code&gt; by a message broker (&lt;a href="https://www.rabbitmq.com/" rel="noopener noreferrer"&gt;rabbitmq&lt;/a&gt; was chosen for that). Furthermore, &lt;a href="https://zipkin.io/" rel="noopener noreferrer"&gt;zipkin&lt;/a&gt; was the trace system chosen (or &lt;code&gt;vendor&lt;/code&gt; as the standard call it), being responsible for getting the application traces and building the distributed tracing diagram:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a&gt;&lt;/a&gt;Figure 1 - Distributed trace
&lt;/h3&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%2Fraw.githubusercontent.com%2Fluizhlelis%2Fdotnet-trace-context%2Fmain%2Fdoc%2Fw3c-trace-context.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%2Fraw.githubusercontent.com%2Fluizhlelis%2Fdotnet-trace-context%2Fmain%2Fdoc%2Fw3c-trace-context.png" alt="Distributed Trace"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first and second APIs have the &lt;a href="https://github.com/luizhlelis/dotnet-trace-context/tree/main/src" rel="noopener noreferrer"&gt;same code base&lt;/a&gt;, but they're being deployed in different containers.&lt;/p&gt;

&lt;h2&gt;
  
  
  OpenTelemetry
&lt;/h2&gt;

&lt;p&gt;An important framework used in the present article to deal with context propagation is &lt;a href="https://opentelemetry.io/" rel="noopener noreferrer"&gt;OpenTelemetry&lt;/a&gt;. As the documentation saids:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;OpenTelemetry is a set of APIs, SDKs, tooling and integrations that are designed for the creation and management of telemetry data such as traces, metrics, and logs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://opentelemetry.io/docs/concepts/glossary/" rel="noopener noreferrer"&gt;OTel&lt;/a&gt; provides a vendor-agnostic instrumentation library to generate, emit, collect, process and export telemetry data. That's not the only purpose of &lt;code&gt;OTel&lt;/code&gt;, which is composed by multiple components: proto, specification, collector, instrumentation libraries. Due to the dense content of &lt;code&gt;OpenTelemetry&lt;/code&gt;, I'll try to approach &lt;code&gt;OTel&lt;/code&gt; in the current article in a shallow way, because that's a subject for another article.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;W3C TraceContext&lt;/code&gt; is one of the &lt;a href="https://github.com/open-telemetry/opentelemetry-specification/blob/b46bcab5fb709381f1fd52096a19541370c7d1b3/specification/context/api-propagators.md#propagators-distribution" rel="noopener noreferrer"&gt;propagators&lt;/a&gt; maintained and distributed as extension packages by &lt;code&gt;OTel&lt;/code&gt;. That's the reason why &lt;code&gt;OTel&lt;/code&gt; is always related to &lt;code&gt;W3C TraceContext&lt;/code&gt; and vice versa.&lt;/p&gt;

&lt;h2&gt;
  
  
  Talk is cheap, show me the code
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;The source code could be found in &lt;a href="https://github.com/luizhlelis/dotnet-trace-context" rel="noopener noreferrer"&gt;this github repo&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The default diagnostics library in &lt;code&gt;.NET 5&lt;/code&gt;, called &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics?view=net-5.0" rel="noopener noreferrer"&gt;System.Diagnostics&lt;/a&gt;, is already prepared to propagate the context based on W3C TraceContext specification. In previous &lt;code&gt;.NET Core&lt;/code&gt; versions, the context was propagated with a &lt;a href="https://github.com/dotnet/runtime/blob/main/src/libraries/System.Diagnostics.DiagnosticSource/src/ActivityUserGuide.md#id-format" rel="noopener noreferrer"&gt;hierarchical identifier format&lt;/a&gt; by default. On &lt;code&gt;.NET Core 3.0&lt;/code&gt;, the identifier format setup started to be available, see &lt;a href="https://stackoverflow.com/questions/61251914/how-can-i-access-w3c-tracecontext-headers-in-a-net-core-3-1-application/67086305#67086305" rel="noopener noreferrer"&gt;this&lt;/a&gt; stackoverflow question for more information about how to configure w3c's format in previous &lt;code&gt;.NET Core&lt;/code&gt; versions.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;first-api&lt;/code&gt; and the &lt;code&gt;second-api&lt;/code&gt; showed in Figure 1 requires three packages to work properly with &lt;code&gt;OpenTelemetry&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;PackageReference&lt;/span&gt; &lt;span class="n"&gt;Include&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"OpenTelemetry.Extensions.Hosting"&lt;/span&gt; &lt;span class="n"&gt;Version&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"1.0.0-rc7"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;PackageReference&lt;/span&gt; &lt;span class="n"&gt;Include&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"OpenTelemetry.Instrumentation.AspNetCore"&lt;/span&gt; &lt;span class="n"&gt;Version&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"1.0.0-rc7"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;PackageReference&lt;/span&gt; &lt;span class="n"&gt;Include&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"OpenTelemetry.Exporter.Zipkin"&lt;/span&gt; &lt;span class="n"&gt;Version&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"1.1.0"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the &lt;code&gt;OpenTelemetry.Extensions.Hosting&lt;/code&gt; package is responsible for register &lt;code&gt;OpenTelemetry&lt;/code&gt; into the application using Dependency Injection, the &lt;code&gt;OpenTelemetry.Instrumentation.AspNetCore&lt;/code&gt; and &lt;code&gt;OpenTelemetry.Exporter.Zipkin&lt;/code&gt; packages represent two source components of &lt;code&gt;OpenTelemetry&lt;/code&gt; framework: the instrumentation library and the collector, respectively. The &lt;a href="https://opentelemetry.io/docs/concepts/instrumenting/" rel="noopener noreferrer"&gt;instrumentation library&lt;/a&gt; is responsible for inject the observable information from libraries and applications into the OpenTelemetry API. On the other hand, the &lt;a href="https://opentelemetry.io/docs/concepts/data-collection/" rel="noopener noreferrer"&gt;collector&lt;/a&gt; offers a vendor-agnostic implementation on how to receive, process, and export telemetry data. The exporter is the place where to send the received data (&lt;code&gt;zipkin&lt;/code&gt; was the chosen for our example). The &lt;code&gt;OTel&lt;/code&gt;'s dependency injection was done in &lt;code&gt;Startup.cs&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;    &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddOpenTelemetryTracing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddAspNetCoreInstrumentation&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetResourceBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ResourceBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateDefault&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;AddService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Zipkin:ServiceName"&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddZipkinExporter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Configure&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ZipkinExporterOptions&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetSection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Zipkin"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the &lt;code&gt;zipkin&lt;/code&gt; endpoint that receives telemetry data is &lt;code&gt;/api/v2/spans&lt;/code&gt;. As mentioned before, the &lt;code&gt;first-api&lt;/code&gt; and the &lt;code&gt;second-api&lt;/code&gt; have the &lt;a href="//../src/OpenTelemetryApi"&gt;same code base&lt;/a&gt;. For this example, the first is called by a client (&lt;code&gt;curl&lt;/code&gt;) in &lt;code&gt;WeatherForecast&lt;/code&gt; route, which calls the second one in the &lt;code&gt;PublishInQueue&lt;/code&gt; route. Both controller methods have a &lt;code&gt;stdout&lt;/code&gt; print for &lt;code&gt;traceparent&lt;/code&gt; and &lt;code&gt;tracestate&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ApiController&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[controller]"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WeatherForecastController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ControllerBase&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;ILogger&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;WeatherForecastController&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_logger&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IHttpClientFactory&lt;/span&gt; &lt;span class="n"&gt;_httpClientFactory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IConfiguration&lt;/span&gt; &lt;span class="n"&gt;_configuration&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;ConnectionFactory&lt;/span&gt; &lt;span class="n"&gt;_connectionFactory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;TextMapPropagator&lt;/span&gt; &lt;span class="n"&gt;_propagator&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Propagators&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DefaultTextMapPropagator&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;WeatherForecastController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;ILogger&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;WeatherForecastController&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;IHttpClientFactory&lt;/span&gt; &lt;span class="n"&gt;httpClientFactory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;IConfiguration&lt;/span&gt; &lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;ConnectionFactory&lt;/span&gt; &lt;span class="n"&gt;connectionFactory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;_logger&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;_httpClientFactory&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;httpClientFactory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;_configuration&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;_connectionFactory&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connectionFactory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;HttpPost&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IActionResult&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;SendToTheOtherApi&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;FromBody&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;WeatherForecast&lt;/span&gt; &lt;span class="n"&gt;weatherForecast&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;_logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Traceparent: {0}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Activity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;_logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Tracestate: {0}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Activity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TraceStateString&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_httpClientFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;StringContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;JsonConvert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SerializeObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;weatherForecast&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;Encoding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UTF8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;PostAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_configuration&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"ClientUrl"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;HttpPost&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"PublishInQueue"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;PublishInQueue&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;FromBody&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;WeatherForecast&lt;/span&gt; &lt;span class="n"&gt;weatherForecast&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JsonConvert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SerializeObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;weatherForecast&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Encoding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UTF8&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;traceparent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Activity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;tracestate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Activity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TraceStateString&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;_logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Traceparent: {0}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;traceparent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;_logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Tracestate: {0}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tracestate&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_connectionFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateConnection&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateModel&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;QueueDeclare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;_configuration&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"RabbitMq:QueueName"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                        &lt;span class="n"&gt;durable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;exclusive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;autoDelete&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;basicProps&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateBasicProperties&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

                    &lt;span class="c1"&gt;// Inject the ActivityContext into the message headers to propagate trace context to the receiving service.&lt;/span&gt;
                    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;contextToInject&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Activity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                    &lt;span class="n"&gt;_propagator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PropagationContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;contextToInject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Baggage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Current&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                        &lt;span class="n"&gt;basicProps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;RabbitMqHelper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InjectTraceContextIntoBasicProperties&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                    &lt;span class="n"&gt;RabbitMqHelper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddMessagingTags&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Activity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Current&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_configuration&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                    &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;BasicPublish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="n"&gt;exchange&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;routingKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;_configuration&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"RabbitMq:QueueName"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                        &lt;span class="n"&gt;basicProperties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;basicProps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that I chose to use a &lt;code&gt;propagator&lt;/code&gt; to inject the context into a carrier. The &lt;code&gt;propagator&lt;/code&gt;s are defined in the &lt;a href="https://github.com/open-telemetry/opentelemetry-specification" rel="noopener noreferrer"&gt;Opentelemetry Specification&lt;/a&gt; as "objects used to read and write context data to and from messages exchanged by the applications". The spec also recommends that &lt;code&gt;propagators&lt;/code&gt; must define &lt;code&gt;Inject&lt;/code&gt; and &lt;code&gt;Extract&lt;/code&gt; operations, as the main purpose of &lt;code&gt;PublishInQueue&lt;/code&gt; is to publish a message, the &lt;code&gt;Inject&lt;/code&gt; context operation suits better there, and the &lt;code&gt;Extract&lt;/code&gt; operation in the &lt;code&gt;worker&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Besides that, the propagation fields (&lt;code&gt;traceparent&lt;/code&gt; and &lt;code&gt;tracestate&lt;/code&gt;) were added in the message header. In the &lt;a href="https://dev.to/luizhlelis/using-w3c-trace-context-standard-in-distributed-tracing-3743"&gt;last article&lt;/a&gt;, I said that the &lt;a href="https://w3c.github.io/trace-context-amqp/" rel="noopener noreferrer"&gt;standard&lt;/a&gt; (in the Working Draft (WD) step of the w3c process) recommends to add the propagation fields in the &lt;code&gt;application-properties&lt;/code&gt; section by the message publisher. For the current example, I chose to propagate that context in the message header even for AMQP calls as was done in &lt;a href="https://github.com/open-telemetry/opentelemetry-dotnet/blob/e3df42bfc15dc1d4dff01d655f669f7c27e35312/examples/MicroserviceExample/Utils/Messaging/MessageSender.cs#L78" rel="noopener noreferrer"&gt;the dotnet OpenTelemetry example&lt;/a&gt;. It's important to reinforce that &lt;code&gt;Trace Context: AMQP protocol&lt;/code&gt; is not a W3C Recommendation yet. Take a look at the place where the propagation fields were added:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;InjectTraceContextIntoBasicProperties&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;IBasicProperties&lt;/span&gt; &lt;span class="n"&gt;props&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Headers&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Headers&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Dictionary&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;object&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default, the &lt;code&gt;ASP.NET core&lt;/code&gt; starts an &lt;code&gt;Activity&lt;/code&gt; span when the &lt;a href="https://github.com/dotnet/aspnetcore/blob/867cec475d18892b828ac44a82d74eccfbbb0e49/src/Hosting/Hosting/src/Internal/HostingApplicationDiagnostics.cs#L65" rel="noopener noreferrer"&gt;request is beginning&lt;/a&gt; and stop it &lt;a href="https://github.com/dotnet/aspnetcore/blob/867cec475d18892b828ac44a82d74eccfbbb0e49/src/Hosting/Hosting/src/Internal/HostingApplicationDiagnostics.cs#L162" rel="noopener noreferrer"&gt;at the end&lt;/a&gt;. For that reason this kind of setup is not required for the &lt;code&gt;first-api&lt;/code&gt; and the &lt;code&gt;second-api&lt;/code&gt;. On the other hand, the manually creation of an activity span is required for the &lt;code&gt;worker&lt;/code&gt; because in that case, it's not dealing with http calls, neither an API, but a message listener.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;NOTE:&lt;/em&gt;&lt;/strong&gt; &lt;code&gt;ASP.NET core&lt;/code&gt; also sets the &lt;code&gt;traceparent&lt;/code&gt; from the upstream request as &lt;a href="https://github.com/dotnet/aspnetcore/blob/main/src/Hosting/Hosting/src/Internal/HostingApplicationDiagnostics.cs#L289" rel="noopener noreferrer"&gt;the current activity ParentId&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For the &lt;code&gt;worker&lt;/code&gt; those packages are required:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;PackageReference&lt;/span&gt; &lt;span class="n"&gt;Include&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"OpenTelemetry.Extensions.Hosting"&lt;/span&gt; &lt;span class="n"&gt;Version&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"1.0.0-rc7"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;PackageReference&lt;/span&gt; &lt;span class="n"&gt;Include&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"OpenTelemetry.Exporter.Zipkin"&lt;/span&gt; &lt;span class="n"&gt;Version&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"1.1.0"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and the &lt;code&gt;OTel&lt;/code&gt;'s dependency injection was configured to the &lt;code&gt;worker&lt;/code&gt; in &lt;code&gt;Program.cs&lt;/code&gt; like the following bellow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddOpenTelemetryTracing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetResourceBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ResourceBuilder&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateDefault&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Zipkin:ServiceName"&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Zipkin:ServiceName"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddZipkinExporter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Configure&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ZipkinExporterOptions&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetSection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Zipkin"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddSingleton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ActivitySource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Zipkin:ServiceName"&lt;/span&gt;&lt;span class="p"&gt;]));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's important to mention that &lt;code&gt;ActivitySource&lt;/code&gt; denotes a &lt;a href="https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#tracer" rel="noopener noreferrer"&gt;Tracer&lt;/a&gt;, which is used to start spans. As mentioned before, for the &lt;code&gt;worker&lt;/code&gt; was required to configure manually a new span scope for each message read:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;MessageHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BasicDeliverEventArgs&lt;/span&gt; &lt;span class="n"&gt;eventArgs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Extract the PropagationContext from the upstream service using message headers.&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;parentContext&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_propagator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Extract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;eventArgs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BasicProperties&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;RabbitMqHelper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExtractTraceContextFromBasicProperties&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;Baggage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Current&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parentContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Baggage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;activity&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_activitySource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StartActivity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;_configuration&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Zipkin:AppName"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="n"&gt;ActivityKind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Consumer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;parentContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ActivityContext&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;eventArgs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToArray&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Encoding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UTF8&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;_logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Received {0}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;_logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Traceparent: {0}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Activity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;_logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Tracestate: {0}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Activity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TraceStateString&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="n"&gt;activity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;RabbitMqHelper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddMessagingTags&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;activity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_configuration&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;MessageHandler&lt;/code&gt; method is triggered when a new message arrives in the queue, so that's the queue listener. Note that a new span scope is created with &lt;code&gt;StartActivity&lt;/code&gt; method and the most important thing is: how to configure the new span scope specifying which is the upstream span. The &lt;code&gt;_propagator&lt;/code&gt; variable is of the type &lt;code&gt;TraceContextPropagator&lt;/code&gt;, an &lt;a href="https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/src/OpenTelemetry.Api/Context/Propagation/TraceContextPropagator.cs" rel="noopener noreferrer"&gt;opentelemetry-dotnet&lt;/a&gt; class that is a text map propagator for W3C trace context. The most important parameter of &lt;code&gt;_propagator.Extract&lt;/code&gt; method is the last one (called &lt;code&gt;getter&lt;/code&gt;), that's the function which &lt;code&gt;OTel&lt;/code&gt; will try to use to extract the propagation fields (&lt;code&gt;traceparent&lt;/code&gt; and &lt;code&gt;tracestate&lt;/code&gt;). Take a look at the way that &lt;code&gt;ExtractTraceContextFromBasicProperties&lt;/code&gt; function was configured to the current example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;ExtractTraceContextFromBasicProperties&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IBasicProperties&lt;/span&gt; &lt;span class="n"&gt;props&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryGetValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Encoding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UTF8&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Enumerable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;as you can see above, the &lt;code&gt;worker&lt;/code&gt; is expecting the &lt;code&gt;traceparent&lt;/code&gt; and &lt;code&gt;tracestate&lt;/code&gt; in the message header.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running the project
&lt;/h2&gt;

&lt;p&gt;Inside &lt;a href="https://github.com/luizhlelis/dotnet-trace-context/tree/main/src" rel="noopener noreferrer"&gt;src folder&lt;/a&gt;, type the command below to up all containers (&lt;code&gt;first-api&lt;/code&gt;, &lt;code&gt;second-api&lt;/code&gt;, &lt;code&gt;worker&lt;/code&gt;, &lt;code&gt;rabbit&lt;/code&gt; and &lt;code&gt;zipkin&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  docker-compose up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;wait for all containers get on and then send a request to the &lt;code&gt;first-api&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--request&lt;/span&gt; POST &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; http://localhost:5000/WeatherForecast &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'accept: */*'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s1"&gt;'{
    "temperatureC": 10,
    "summary": "Trace Test"
}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the message that you sent above will travel throughout the flow (&lt;code&gt;first-api&lt;/code&gt; &amp;gt; &lt;code&gt;second-api&lt;/code&gt; &amp;gt;  &lt;code&gt;rabbit&lt;/code&gt; &amp;gt; &lt;code&gt;worker&lt;/code&gt;) along with the propagation fields (&lt;code&gt;traceparent&lt;/code&gt; and &lt;code&gt;tracestate&lt;/code&gt;). Take a look at the application &lt;code&gt;stdout&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;first-api     | info: OpenTelemetryApi.Controllers.WeatherForecastController[0]
first-api     |       Traceparent: 00-0a0578c18192c14bae738b777e072a42-2db0e8c6b4654744-01
first-api     | info: OpenTelemetryApi.Controllers.WeatherForecastController[0]
first-api     |       Tracestate: (null)
second-api    | info: OpenTelemetryApi.Controllers.WeatherForecastController[0]
second-api    |       Traceparent: 00-0a0578c18192c14bae738b777e072a42-bfc08418aeb71a4e-01
second-api    | info: OpenTelemetryApi.Controllers.WeatherForecastController[0]
second-api    |       Tracestate: (null)
worker        | info: Worker.WorkerService[0]
worker        |       Traceparent: 00-0a0578c18192c14bae738b777e072a42-004468438f2d724c-01
worker        | info: Worker.WorkerService[0]
worker        |       Tracestate: (null)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;note that the &lt;code&gt;trace-id&lt;/code&gt; (&lt;code&gt;0a0578c18192c14bae738b777e072a42&lt;/code&gt;) remains the same throughout all the trace, and the &lt;code&gt;span-id&lt;/code&gt; (or &lt;code&gt;parent-id&lt;/code&gt;) has been updated between the applications (&lt;code&gt;2db0e8c6b4654744&lt;/code&gt;, &lt;code&gt;bfc08418aeb71a4e&lt;/code&gt; and &lt;code&gt;004468438f2d724c&lt;/code&gt;). To see the generated distributed tracing diagram, access &lt;code&gt;zipkin&lt;/code&gt; in your browser:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  http://localhost:9411/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;at home page, let the search field empty and type &lt;code&gt;RUN QUERY&lt;/code&gt; to load all traces. Finally, click in your trace, then you'll see a diagram like this:&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%2Fraw.githubusercontent.com%2Fluizhlelis%2Fdotnet-trace-context%2Fmain%2Fdoc%2Fzipkin-diagram.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%2Fraw.githubusercontent.com%2Fluizhlelis%2Fdotnet-trace-context%2Fmain%2Fdoc%2Fzipkin-diagram.png" alt="Zipkin Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;The W3C Trace Context standard came to define a standard to the distributed tracing propagation. Currently, there is only one &lt;code&gt;W3C Recommendation&lt;/code&gt; which is for HTTP calls (launched in february 2020), all the other standards are in the &lt;code&gt;working in process&lt;/code&gt; step (AMQP, MQTT and baggage). It doesn't mean that you should avoid to use the standard in a production environment, but keep in mind that some things are going to change and is important to be up to date with newer releases.&lt;/p&gt;

&lt;p&gt;If you got until here and liked the article content, let me know reacting to the current post. You can also open a discussion below, I'll try to answer soon. On the other hand, if you think that I said something wrong, please open an issue in the &lt;a href="https://github.com/luizhlelis/dotnet-trace-context" rel="noopener noreferrer"&gt;article's github repo&lt;/a&gt;. In the next article, I'll show a full distributed trace example in a microsservice architecture, just like this, but using &lt;code&gt;python&lt;/code&gt; with &lt;code&gt;django&lt;/code&gt;. Hope you like it!&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;DRUTU, Bogdan; KANZHELEV, Sergey; MCLEAN, Morgan; MOLNAR, Nik; REITBAUER, Alois; SHKURO, Yuri. &lt;a href="https://www.w3.org/TR/trace-context/" rel="noopener noreferrer"&gt;W3C Recommendation - Trace Context&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;KANZHELEV, Sergey; VASTERS, Clemens. &lt;a href="https://w3c.github.io/trace-context-amqp/" rel="noopener noreferrer"&gt;W3C Editor's draft - Trace Context: AMQP protocol&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;OPENTELEMETRY, Community. &lt;a href="https://github.com/open-telemetry/opentelemetry-dotnet" rel="noopener noreferrer"&gt;OpenTelemetry .NET&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;OPENTELEMETRY, Community. &lt;a href="https://opentelemetry.io/docs/" rel="noopener noreferrer"&gt;OpenTelemetry Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;OPENTELEMETRY, Community. &lt;a href="https://github.com/open-telemetry/opentelemetry-specification" rel="noopener noreferrer"&gt;OpenTelemetry Specification&lt;/a&gt;&lt;/p&gt;

</description>
      <category>tracecontext</category>
      <category>distributedtracing</category>
      <category>opentelemetry</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Using W3C Trace Context standard in distributed tracing</title>
      <dc:creator>Luiz Lelis</dc:creator>
      <pubDate>Sun, 09 May 2021 03:27:45 +0000</pubDate>
      <link>https://dev.to/luizhlelis/using-w3c-trace-context-standard-in-distributed-tracing-3743</link>
      <guid>https://dev.to/luizhlelis/using-w3c-trace-context-standard-in-distributed-tracing-3743</guid>
      <description>&lt;p&gt;In the software development process, when a system experiences a failure in runtime, it's natural for a developer to try to link that failure with who called that method and also which was the original request. This is where &lt;a href="https://en.wikipedia.org/wiki/Stack_trace" rel="noopener noreferrer"&gt;stack trace&lt;/a&gt; comes in, look at an example below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Unhandled exception. System.InvalidOperationException: Stack trace example
   at Program.CallChildActivity&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; /Users/luizhlelis/Documents/projects/personal/trace-context-w3c/src/system-diagnostics-activity/Program.cs:line 22
   at Program.Main&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; /Users/luizhlelis/Documents/projects/personal/trace-context-w3c/src/system-diagnostics-activity/Program.cs:line 11
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;with the information above we're able to know that a failure happened at &lt;code&gt;CallChildActivity()&lt;/code&gt; method (line 22) which was called by the &lt;code&gt;Main()&lt;/code&gt; method (line 11) both inside the &lt;code&gt;Program.cs&lt;/code&gt; class. That's the reason why the runtime message tracking is essential for a software health and reliability, a rich information like that greatly increases the troubleshoot productivity. So the &lt;code&gt;stack trace&lt;/code&gt; suits very well in terms of message trace when the subject is a single process application, like monolithic systems. On the other hand, when dealing with distributed systems like in a microservice architecture, the stack trace is not enough to expose the entire message tracking. That's the reason why distributed tracing tools and standards became necessary. The W3C defines a standard for this type of tracking, which is called &lt;code&gt;Trace Context&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  W3C Trace Context purpose
&lt;/h2&gt;

&lt;p&gt;Imagine a system designed as a microservice architecture where two APIs communicate in a synchronous way (http calls) and the second API communicates with a worker by a message broker:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a&gt;&lt;/a&gt;Figure 1 - Distributed trace
&lt;/h3&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%2Fraw.githubusercontent.com%2Fluizhlelis%2Ftrace-context-w3c%2Fmain%2Fdoc%2Fdistributed-trace.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%2Fraw.githubusercontent.com%2Fluizhlelis%2Ftrace-context-w3c%2Fmain%2Fdoc%2Fdistributed-trace.png" alt="distributed-trace"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;just like the &lt;code&gt;stack trace&lt;/code&gt;, every &lt;code&gt;Activity&lt;/code&gt; needs an Id to be identifiable and also needs to know the &lt;code&gt;Activity&lt;/code&gt; Id of who called it. With the purpose of solving this kind of problem, some vendors came up delivering not only the distributed trace message information but also the application performance, the load time, the application's response time, and other stuff. That kind of vendor is called Application Performance Management tools (APM tools) or also trace systems, below are some examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dynatrace&lt;/li&gt;
&lt;li&gt;New Relic&lt;/li&gt;
&lt;li&gt;Application Insights&lt;/li&gt;
&lt;li&gt;Elastic APM&lt;/li&gt;
&lt;li&gt;Zipkin&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;NOTE:&lt;/em&gt;&lt;/strong&gt;  I chose to use the term &lt;code&gt;vendor&lt;/code&gt; to describe all the trace systems because that's the way as the standard refers to them. But it seems that &lt;a href="https://github.com/w3c/trace-context/issues/387" rel="noopener noreferrer"&gt;it'll be changed soon&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;now imagine a scenario where there are many vendors and also many languages with different diagnostics libraries, some of them identify a trace with an &lt;code&gt;operation-id&lt;/code&gt;, other calls it as &lt;code&gt;request-id&lt;/code&gt; and also there is another one which recognizes it as a &lt;code&gt;trace-id&lt;/code&gt;. Besides that, the id's format changes depending on vendor or diagnostic library: one is in the &lt;code&gt;hierarchical&lt;/code&gt; format, another one is an &lt;code&gt;UUID&lt;/code&gt; and there is also a 24 character &lt;code&gt;string&lt;/code&gt; identifier. That scenario would result in: systems with different tracing vendors will not be able to correlate the traces and also will not be able to propagate traces as there is no unique identification that is forwarded. This is where trace context standard comes in.&lt;/p&gt;

&lt;h2&gt;
  
  
  The trace context standard
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://www.w3.org/TR/trace-context/" rel="noopener noreferrer"&gt;W3C Trace Context&lt;/a&gt; specification defines a standard to HTTP headers and formats to propagate the distributed tracing context information. It defines two fields that should be propagated in the http request's header throughout the trace flow. Take a look below at the standard definition of each field:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;traceparent&lt;/code&gt;: identifier responsible to describe the incoming request position in its trace graph. It represents a common format of the incoming request in a tracing system, understood by all vendors.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;tracestate&lt;/code&gt;: extends traceparent with vendor-specific data represented by a set of name/value pairs. Storing information in tracestate is optional.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;traceparent&lt;/code&gt; field
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;traceparent&lt;/code&gt; field uses the Augmented Backus-Naur Form (ABNF) notation of &lt;a href="https://www.w3.org/TR/trace-context/#bib-rfc5234" rel="noopener noreferrer"&gt;RFC5234&lt;/a&gt; and is composed by 4 sub-fields:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;version&lt;/code&gt; - &lt;code&gt;traceid&lt;/code&gt; - &lt;code&gt;parentid/spanid&lt;/code&gt; - &lt;code&gt;traceflags&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;NOTE:&lt;/em&gt;&lt;/strong&gt;  &lt;code&gt;sub-field&lt;/code&gt; term is unofficial, I chose this term for didactic purposes only&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;00-480e22a2781fe54d992d878662248d94-b4b37b64bb3f6141-00
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;version&lt;/code&gt; (8-bit): trace context version that the system has adopted. The current is &lt;code&gt;00&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;trace-id&lt;/code&gt; (16-byte array): the ID of the whole trace. It's used to identify a distributed trace globally through a system.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;parent-id&lt;/code&gt; / &lt;code&gt;span-id&lt;/code&gt; (8-byte array): used to identify the parent of the current span on incoming requests or the current span on an outgoing request.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;trace-flags&lt;/code&gt; (8-bit): flags that represent recommendations of the caller. Can be also thought as the caller recommendations and are strict to three reasons: trust and abuse, bug in the caller or different load between caller and callee service.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;NOTE:&lt;/em&gt;&lt;/strong&gt; all the fields are encoded as &lt;code&gt;hexadecimal&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Therefore, applying the trace context concept in an application like the Figure 1 will result in the diagram below:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a&gt;&lt;/a&gt;Figure 2 - Propagation fields
&lt;/h3&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%2Fraw.githubusercontent.com%2Fluizhlelis%2Ftrace-context-w3c%2Fmain%2Fdoc%2Fw3c-trace-context.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%2Fraw.githubusercontent.com%2Fluizhlelis%2Ftrace-context-w3c%2Fmain%2Fdoc%2Fw3c-trace-context.png" alt="propagation-fields"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;note that the &lt;code&gt;trace-id&lt;/code&gt; is an identifier of all the trace, the &lt;code&gt;parent-id&lt;/code&gt; identifies a delimited scope of the whole trace. Moreover, the &lt;code&gt;traceparent&lt;/code&gt; along with the &lt;code&gt;tracestate&lt;/code&gt; have been propagated throughout the trace flow.&lt;/p&gt;

&lt;p&gt;To describe better the &lt;code&gt;traceparent&lt;/code&gt; dynamics, take a look at the example below, wrote in c#, where two spans scopes are generated and the context is being propagated throughout them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Diagnostics&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;upstreamActivity&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Activity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Upstream"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;upstreamActivity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;upstreamActivity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OperationName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"traceparent: {0}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;upstreamActivity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;CallChildActivity&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;upstreamActivity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Stop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadKey&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;CallChildActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;downstreamActivity&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Activity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Downstream Dependency"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;downstreamActivity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;downstreamActivity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OperationName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"traceparent: {0}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;downstreamActivity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;downstreamActivity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Stop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;NOTE:&lt;/em&gt;&lt;/strong&gt; the &lt;code&gt;System.Diagnostics.Activity&lt;/code&gt; library in .net 5 has already been configured as the w3c standard&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;even though the example above shows a single process application, that's the pattern specified by the Trace Context standard. Basically, what that program is doing is: first it opens an upstream span scope and print the &lt;code&gt;traceparent&lt;/code&gt; in the stdout, then it calls a downstream method which opens another span scope and also prints its &lt;code&gt;traceparent&lt;/code&gt; and close the scope. After that, the upstream span scope was closed after all of it. The systems output follow below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Upstream
traceparent: 00-3e425f2373d89640bde06e8285e7bf88-9a5fdefae3abb440-00

Downstream Dependency
traceparent: 00-3e425f2373d89640bde06e8285e7bf88-0767a6c6c1240f47-00
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;note that the &lt;code&gt;trace-id&lt;/code&gt; (3e425f2373d89640bde06e8285e7bf88) is been maintained by the whole trace and the &lt;code&gt;parent-id&lt;/code&gt; is changing based on the span scope (the upstream is equals to 9a5fdefae3abb440 and the downstream is 0767a6c6c1240f47).&lt;/p&gt;

&lt;p&gt;In some cases, &lt;code&gt;parent-id&lt;/code&gt; could cause confusion due to its name, but that name is based on the vision of incoming requests. So one must think in the endpoint side, for example: imagine the message that had just arrived in the controller, the &lt;code&gt;traceparent&lt;/code&gt; received in the header hasn't had his &lt;code&gt;parent-id&lt;/code&gt; updated yet by the midleware, so in that vision the id inside &lt;code&gt;traceparent&lt;/code&gt; is the upstream id or also the id of its parent.&lt;/p&gt;

&lt;p&gt;There is a Working Draft (WD) document, the &lt;a href="https://w3c.github.io/trace-context/" rel="noopener noreferrer"&gt;Trace Context Level 2&lt;/a&gt;, that has an response standard where the &lt;code&gt;parent-id&lt;/code&gt; calls &lt;code&gt;child-id&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;NOTE:&lt;/em&gt;&lt;/strong&gt; See &lt;a href="https://www.w3.org/2017/Process-20170301/#working-draft" rel="noopener noreferrer"&gt;w3c process&lt;/a&gt; for more information about the steps until a document become a w3c recomendation&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;tracestate&lt;/code&gt; field
&lt;/h2&gt;

&lt;p&gt;The standard uses a fictitious example to describe what is &lt;code&gt;tracestate&lt;/code&gt; for, I will reproduce it in this article. Imagine a client and server system that use different trace vendors, the first is called Congo and the second is called Rojo. A client traced in the Congo system adds in &lt;code&gt;tracestate&lt;/code&gt; the vendor-specific id (with its specific format): &lt;code&gt;tracestate: congo=t61rcWkgMzE&lt;/code&gt;. So the outbound HTTP request will be enriched with the headers below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;traceparent: 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01

tracestate: &lt;span class="nv"&gt;congo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;t61rcWkgMzE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;any other user-supplied information (different from vendor-specific info) should be added in the &lt;a href="https://w3c.github.io/baggage/" rel="noopener noreferrer"&gt;baggage&lt;/a&gt; field, that's another standard which is in Working Draft (WD) step of the &lt;a href="https://www.w3.org/2017/Process-20170301/#working-draft" rel="noopener noreferrer"&gt;w3c process&lt;/a&gt; (is not a w3c recomendation yet).&lt;/p&gt;

&lt;h2&gt;
  
  
  Trace Context: AMQP protocol
&lt;/h2&gt;

&lt;p&gt;As displayed in Figure 2, in a microservice architecture, it's common to propagate messages throw a broker. For that kind of operation, there is another document that specifies the pattern (in case of using AMQP protocol), is the &lt;a href="https://w3c.github.io/trace-context-amqp/" rel="noopener noreferrer"&gt;Trace Context: AMQP protocol&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Trace Context: AMQP protocol&lt;/code&gt; is another example of document in the Working Draft (WD) step of the &lt;a href="https://www.w3.org/2017/Process-20170301/#working-draft" rel="noopener noreferrer"&gt;w3c process&lt;/a&gt;. That standard specifies the trace context fields placement in the message different from the HTTP standard.&lt;/p&gt;

&lt;p&gt;The standard recomends that the fields &lt;code&gt;traceparent&lt;/code&gt; and &lt;code&gt;tracestate&lt;/code&gt; should be added to the message in the &lt;code&gt;application-properties&lt;/code&gt; section by message publisher. On the message readers side, the trace context should be built by reading &lt;code&gt;traceparent&lt;/code&gt; and &lt;code&gt;tracestate&lt;/code&gt; fields from the &lt;code&gt;message-annotations&lt;/code&gt; first and if not exist, from &lt;code&gt;application-properties&lt;/code&gt;. See below the message format in the AMQP protocol:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a&gt;&lt;/a&gt;Figure 3 - AMQP message format
&lt;/h3&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%2Fraw.githubusercontent.com%2Fluizhlelis%2Ftrace-context-w3c%2Fmain%2Fdoc%2Famqp-message-format.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%2Fraw.githubusercontent.com%2Fluizhlelis%2Ftrace-context-w3c%2Fmain%2Fdoc%2Famqp-message-format.png" alt="amqp-message-format"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The reason for the trace context fields placement in the message is that the &lt;code&gt;application-properties&lt;/code&gt; section is defined by the message publisher and the brokers cannot mutate those properties because that section is immutable. On the other hand, the section &lt;code&gt;message-annotations&lt;/code&gt; is designed for message brokers usage. In other words, the fields inside that section can be mutated during the message processing. So it means that in case the need arises to annotate the message inside the middleware as it flows, that must happen in the &lt;code&gt;message-annotations&lt;/code&gt; section, using the fields sent by the publisher in &lt;code&gt;application-properties&lt;/code&gt; as a base.&lt;/p&gt;

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

&lt;p&gt;The W3C Trace Context standard came to define a pattern to the distributed tracing process. Currently, there is only one &lt;code&gt;W3C Recommendation&lt;/code&gt; which is for HTTP calls (lauched in february 2020), all the other standards are in working in process (AMQP, MQTT and baggage). It doesn't means that you should avoid to use the standard in a production environment, but keep in mind that some things are going to change and it's important to be up to date with newer releases.&lt;/p&gt;

&lt;p&gt;If you got until here and liked the article content, let me know reacting to the current post. You can also open a discussion below, I'll try to answer soon. On the other hand, if you think that I said something wrong, please open an issue in the &lt;a href="https://github.com/luizhlelis/trace-context-w3c" rel="noopener noreferrer"&gt;article's github repo&lt;/a&gt;. In the next article, I'll show a full distributed trace example using the trace context concept (in a microsservice architecture using &lt;code&gt;.NET 5&lt;/code&gt;). Hope you like it!&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;BOGARD, Jimmy. &lt;a href="https://jimmybogard.com/building-end-to-end-diagnostics-and-tracing-a-primer-trace-context/" rel="noopener noreferrer"&gt;Building End-to-End Diagnostics and Tracing: Trace Context&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;DRUTU, Bogdan; KANZHELEV, Sergey; MCLEAN, Morgan; MOLNAR, Nik; REITBAUER, Alois; SHKURO, Yuri. &lt;a href="https://www.w3.org/TR/trace-context/" rel="noopener noreferrer"&gt;W3C Recommendation - Trace Context&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;DRUTU, Bogdan; KANZHELEV, Sergey; MCLEAN, Morgan; MOLNAR, Nik; REITBAUER, Alois; SHKURO, Yuri. &lt;a href="https://w3c.github.io/trace-context/" rel="noopener noreferrer"&gt;W3C Recommendation - Trace Context Level 2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;GODFREY, Robert; INGHAM, David; SCHLOMING, Rafael. &lt;a href="http://docs.oasis-open.org/amqp/core/v1.0/os/amqp-core-messaging-v1.0-os.html" rel="noopener noreferrer"&gt;Advanced Message Queuing Protocol (AMQP) Version 1.0, Part 3: Messaging&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;KANZHELEV, Sergey; MCLEAN, Morgan, REITBAUER, Alois. &lt;a href="https://w3c.github.io/baggage/" rel="noopener noreferrer"&gt;W3C Editor's draft - Propagation format for distributed trace context: Baggage&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;KANZHELEV, Sergey; VASTERS, Clemens. &lt;a href="https://w3c.github.io/trace-context-amqp/" rel="noopener noreferrer"&gt;W3C Editor's draft - Trace Context: AMQP protocol&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;KANZHELEV, Sergey; VASTERS, Clemens. &lt;a href="https://w3c.github.io/trace-context-mqtt/" rel="noopener noreferrer"&gt;W3C Editor's draft - Trace Context: MQTT protocol&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;NEVILE, Charles M. &lt;a href="https://www.w3.org/2017/Process-20170301/" rel="noopener noreferrer"&gt;World Wide Web Consortium Process Document&lt;/a&gt;&lt;/p&gt;

</description>
      <category>tracecontext</category>
      <category>distributedtracing</category>
      <category>distributedsystems</category>
      <category>opentelemetry</category>
    </item>
  </channel>
</rss>
