<?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: mrasu</title>
    <description>The latest articles on DEV Community by mrasu (@mrasu).</description>
    <link>https://dev.to/mrasu</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%2F1255752%2F3d76831c-a9d2-41b6-bcfa-5041903f2696.jpeg</url>
      <title>DEV Community: mrasu</title>
      <link>https://dev.to/mrasu</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mrasu"/>
    <language>en</language>
    <item>
      <title>Observable API Testing with YAML using Echoed</title>
      <dc:creator>mrasu</dc:creator>
      <pubDate>Thu, 22 Feb 2024 15:14:55 +0000</pubDate>
      <link>https://dev.to/mrasu/observable-api-testing-with-yaml-using-echoed-3ed3</link>
      <guid>https://dev.to/mrasu/observable-api-testing-with-yaml-using-echoed-3ed3</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;I'm building a package that makes integration testing easy by visualizing OpenTelemetry's traces and logs.&lt;/p&gt;

&lt;p&gt;GitHub is 👉 👉 &lt;a href="https://github.com/mrasu/echoed"&gt;https://github.com/mrasu/echoed&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Echoed
&lt;/h2&gt;

&lt;p&gt;Echoed enhances Integration testing, aka API testing by visualizing OpenTelemetry's traces and logs.&lt;br&gt;
Because it is built on top of Jest, it holds Jest's features like parallel execution or debuggability.&lt;br&gt;
In addition to those features, Echoed offers unique capabilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Coverage Analysis&lt;/strong&gt;: Gain insights into the coverage of your API endpoints based on OpenAPI or Protocol Buffers specifications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Detect Propagation Leaks&lt;/strong&gt;: Uncover spans that don't propagate OpenTelemetry's context to their children.&lt;/li&gt;
&lt;li&gt;etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is an overview of Echoed&lt;br&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%2Fon9uxc3ufhnnyu0awzt6.jpg" 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%2Fon9uxc3ufhnnyu0awzt6.jpg" alt="How echoed works" width="800" height="428"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Echoed now suppors YAML!
&lt;/h2&gt;

&lt;p&gt;Because Echoed is working with Jest, JavaScript and TypeScript are originally supported.&lt;br&gt;
And now, you can also write tests with YAML!&lt;br&gt;
With this, you can create tests with less effort and it requires little knowledge about JavaScript or TypeScript.&lt;/p&gt;

&lt;p&gt;YAML is like below:&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;variable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;productId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;OLJCESPC7Z&lt;/span&gt;
&lt;span class="na"&gt;scenarios&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Get product detail&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;fetch /products/{id}&lt;/span&gt;
        &lt;span class="na"&gt;act&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;runner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;fetch&lt;/span&gt;
          &lt;span class="na"&gt;argument&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;endpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http://localhost:8080/products/${productId}&lt;/span&gt;
        &lt;span class="na"&gt;assert&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;expect(_.response.status).toBe(200)&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;expect(_.jsonBody.id).toBe(productId)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above YAML.&lt;br&gt;
The test does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a request to &lt;code&gt;http://localhost:8080/products/${productId}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Check status code of the response is &lt;code&gt;200&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Check body of the response is JSON and value of &lt;code&gt;id&lt;/code&gt; in the JSON is &lt;code&gt;OLJCESPC7Z&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After writing the YAML, Echoed compiles it to TypeScript using &lt;code&gt;npx echoed compile&lt;/code&gt;.&lt;br&gt;
Then, you can run test by &lt;code&gt;npx jest&lt;/code&gt; without knowing TypeScript for it.&lt;/p&gt;

&lt;p&gt;Additionally, Echoed generates an HTML report for the tests.&lt;br&gt;
It contains OpenTelemetry's data and coverage for each service.&lt;/p&gt;

&lt;p&gt;Here are the screenshots of these features&lt;br&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%2Ft4ynb78xxtnm072es724.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%2Ft4ynb78xxtnm072es724.png" alt="Trace" width="800" height="778"&gt;&lt;/a&gt;&lt;br&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%2Fhboxhbocqins371gjykr.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%2Fhboxhbocqins371gjykr.png" alt="Coverage" width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Complex example
&lt;/h2&gt;

&lt;p&gt;When you want to tests more complicated flow like retry or set up database, Echoed supports them.&lt;br&gt;
Below YAML does more things:&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;retry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt; &lt;span class="c1"&gt;# &amp;lt;- retry failed tests.&lt;/span&gt;
&lt;span class="na"&gt;variable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;productId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;OLJCESPC7Z&lt;/span&gt; &lt;span class="c1"&gt;# &amp;lt;- define variables.&lt;/span&gt;
  &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${connectDB()}&lt;/span&gt;
&lt;span class="na"&gt;runners&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;runner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;fetch&lt;/span&gt;
    &lt;span class="na"&gt;option&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;baseEndpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${_env.BASE_ENDPOINT}/api&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;content-type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;application/json&lt;/span&gt;
&lt;span class="na"&gt;hook&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;beforeEach&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# &amp;lt;- set up DB before each test&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;db.insertProduct(productId)&lt;/span&gt;
  &lt;span class="na"&gt;afterEach&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;db.cleanup()&lt;/span&gt; &lt;span class="c1"&gt;# &amp;lt;- clear DB&lt;/span&gt;
&lt;span class="na"&gt;scenarios&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Adding item to cart&lt;/span&gt;
    &lt;span class="na"&gt;variable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1234&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Add a product to cart&lt;/span&gt;
        &lt;span class="na"&gt;arrange&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;db.createUser(userId)&lt;/span&gt; &lt;span class="c1"&gt;# &amp;lt;- establish preconditions&lt;/span&gt;
        &lt;span class="na"&gt;act&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;runner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;fetch&lt;/span&gt; &lt;span class="c1"&gt;# &amp;lt;- executes HTTP request&lt;/span&gt;
          &lt;span class="na"&gt;argument&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;endpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cart?currencyCode=USD&lt;/span&gt;
            &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;POST&lt;/span&gt;
            &lt;span class="na"&gt;jsonBody&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;productId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${productId}&lt;/span&gt;
                &lt;span class="na"&gt;quantity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
              &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${userId}&lt;/span&gt;
        &lt;span class="na"&gt;assert&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;  &lt;span class="c1"&gt;# &amp;lt;- test anything&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;expect(_.response.status).toBe(200)&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;expect(_.jsonBody).toEqual({&lt;/span&gt;
              &lt;span class="s"&gt;items: [{&lt;/span&gt;
                &lt;span class="s"&gt;productId: productId,&lt;/span&gt;
                &lt;span class="s"&gt;quantity: 1&lt;/span&gt;
              &lt;span class="s"&gt;}],&lt;/span&gt;
              &lt;span class="s"&gt;userId: userId,&lt;/span&gt;
            &lt;span class="s"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It does,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create required data in &lt;code&gt;beforeEach&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Establish preconditions in &lt;code&gt;arrange&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Create an HTTP request in &lt;code&gt;act&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Check the response is what you want in &lt;code&gt;assert&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Then delete data in &lt;code&gt;afterEach&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Echoed's YAML respects the AAA(Act-Arrange-Assert) pattern. So you can separate code for preparing data and code that actually you want to test.&lt;/p&gt;

&lt;p&gt;You can see more examples at &lt;a href="https://github.com/mrasu/echoed/tree/main/create-echoed/template/jest/example/scenario"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus. Using Echoed without OpenTelemetry
&lt;/h2&gt;

&lt;p&gt;While the primary feature of Echoed is troubleshooting or analyzing tests by visualizing OpenTelemetry data, it can also be used to write Jest tests in YAML.&lt;br&gt;
Because conversion from YAML to Jest test (TypeScript) doesn't use OpenTelemetry, even when you haven't had time to install OpenTelemetry to you project, you can write tests with YAML using Echoed.&lt;/p&gt;




&lt;p&gt;That's all!&lt;br&gt;
Echoed has more features making test easy.&lt;br&gt;
Visit GitHub! 👉👉 &lt;a href="https://github.com/mrasu/echoed"&gt;https://github.com/mrasu/echoed&lt;/a&gt; 👈👈&lt;/p&gt;

&lt;p&gt;I'd appreciate any feedback – whether you liked it or not!&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>webdev</category>
      <category>testing</category>
      <category>opensource</category>
    </item>
    <item>
      <title>How OpenTelemetry Organizes Distributed Tracing</title>
      <dc:creator>mrasu</dc:creator>
      <pubDate>Thu, 01 Feb 2024 13:44:14 +0000</pubDate>
      <link>https://dev.to/mrasu/how-opentelemetry-organizes-distributed-tracing-3m4p</link>
      <guid>https://dev.to/mrasu/how-opentelemetry-organizes-distributed-tracing-3m4p</guid>
      <description>&lt;p&gt;OpenTelemetry is a framework for sending traces, metrics, and logs. It consists of various components, such as protocols and SDKs tailored for many programming languages.&lt;/p&gt;

&lt;p&gt;This article explores how OpenTelemetry accomplishes distributed tracing and delves into the underlying mechanisms that make it work.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Distributed Tracing?
&lt;/h2&gt;

&lt;p&gt;Distributed tracing is a vital mechanism for monitoring and tracking traces across multiple servers, commonly employed in microservices architectures.&lt;/p&gt;

&lt;p&gt;OpenTelemetry's distributed tracing primarily consists of two elements: &lt;code&gt;Trace&lt;/code&gt; and &lt;code&gt;Span&lt;/code&gt;.&lt;br&gt;
A &lt;code&gt;Span&lt;/code&gt; contains execution details such as timestamps or SQL query, while a &lt;code&gt;Trace&lt;/code&gt; is a tree structure with Span as its nodes.&lt;/p&gt;

&lt;p&gt;In the visual representation below, the entire figure represents a &lt;code&gt;Trace&lt;/code&gt;, and each bar represents a &lt;code&gt;Span&lt;/code&gt;.&lt;br&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%2Fvn0egisj6pmimkadczag.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%2Fvn0egisj6pmimkadczag.png" alt="Image of Trace" width="800" height="509"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's important to note that a &lt;code&gt;Trace&lt;/code&gt; is not a tangible entity; programs generate only &lt;code&gt;Span&lt;/code&gt;.&lt;br&gt;
The backend organizes a &lt;code&gt;Trace&lt;/code&gt; from received &lt;code&gt;Spans&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Generating Traces from Spans
&lt;/h2&gt;

&lt;p&gt;Distributed tracing can be achieved when the backend constructs a &lt;code&gt;Trace&lt;/code&gt; based on &lt;code&gt;Spans&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To create a Trace based on &lt;code&gt;Spans&lt;/code&gt;, you need to consider three key elements within the &lt;code&gt;Span&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;TraceId&lt;/li&gt;
&lt;li&gt;SpanId&lt;/li&gt;
&lt;li&gt;ParentSpanId&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can find them in the OpenTelemetry Proto file, specifically in the &lt;a href="https://github.com/open-telemetry/opentelemetry-proto/blob/b5c1a7882180a26bb7794594e8546798ecb68103/opentelemetry/proto/trace/v1/trace.proto#L83-L110"&gt;trace.proto&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;TraceID&lt;/strong&gt;: This is the unique identifier for the entire trace. If, for instance, the &lt;code&gt;TraceID&lt;/code&gt; is &lt;code&gt;9023c11c...&lt;/code&gt; in hexadecimal, any span sharing this TraceID (&lt;code&gt;9023c11c...&lt;/code&gt;) is part of the same trace.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SpanId&lt;/strong&gt;: Each &lt;code&gt;Span&lt;/code&gt; has a unique identifier within the same &lt;code&gt;Trace&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ParentSpanId&lt;/strong&gt;: This is the identifier of the parent span. When the &lt;code&gt;SpanId&lt;/code&gt; of one Span matches the &lt;code&gt;ParentSpanId&lt;/code&gt; of another, the Span is considered as the parent of another one.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By combining these elements, we can construct a &lt;code&gt;Trace&lt;/code&gt; tree.&lt;br&gt;
Let's illustrate this with an example:&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%2Fmddbii9fkd5vwv8sdfsm.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%2Fmddbii9fkd5vwv8sdfsm.png" alt="Image of Trace" width="800" height="637"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this example, observe that the &lt;code&gt;ParentSpanId&lt;/code&gt; of Spans matches the &lt;code&gt;SpanId&lt;/code&gt; of their parent, while different TraceId give rise to different trees.&lt;/p&gt;
&lt;h2&gt;
  
  
  Propagation in Distributed Tracing
&lt;/h2&gt;

&lt;p&gt;As established in the previous chapter, we learned that Traces can be constructed from elements in Spans.&lt;/p&gt;

&lt;p&gt;Now, the question arises: How does a program determine its own &lt;code&gt;TraceId&lt;/code&gt; and &lt;code&gt;ParentSpanId&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;While sharing &lt;code&gt;TraceId&lt;/code&gt; within the same process can be achieved through memory, distributed tracing in a multi-machine environment necessitates a more sophisticated approach.&lt;/p&gt;

&lt;p&gt;This is where Propagation becomes essential.&lt;/p&gt;

&lt;p&gt;The idea is simple: "Pass your TraceId and SpanId to other machines somehow."&lt;br&gt;
For instance, when making an HTTP request, you can include these identifiers in the headers.&lt;/p&gt;

&lt;p&gt;There are some methods for transmitting this information in HTTP headers, due to historical reasons, but I'll focus on the approach standardized by the W3C, which has gained adoption in the industry.&lt;/p&gt;
&lt;h3&gt;
  
  
  W3C Trace Context
&lt;/h3&gt;

&lt;p&gt;The format of the &lt;a href="https://www.w3.org/TR/trace-context/"&gt;W3C Trace Context&lt;/a&gt; is specified by the W3C, as indicated by its name.&lt;/p&gt;

&lt;p&gt;When utilizing W3C Trace Context, the &lt;code&gt;traceparent&lt;/code&gt; field is employed in the HTTP request header.&lt;/p&gt;

&lt;p&gt;The header follows the format &lt;code&gt;${version}-${trace-id}-${parent-id}-${trace-flags}&lt;/code&gt;.&lt;br&gt;
When using &lt;code&gt;curl&lt;/code&gt;, it looks like the 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;curl &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"traceparent:00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  localhost
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This example demonstrates how the &lt;code&gt;traceparent&lt;/code&gt; field is included in an HTTP request header, conveying essential trace information to the destination:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Version: &lt;code&gt;00&lt;/code&gt; (currently, there is no version other than 00)&lt;/li&gt;
&lt;li&gt;TraceId: &lt;code&gt;4bf92f3577b34da6a3ce929d0e0e4736&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;ParentSpanId: &lt;code&gt;00f067aa0ba902b7&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Flag: &lt;code&gt;01&lt;/code&gt; at the end indicates whether the request is being sampled or not.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This header enables the sharing of Trace information with another service.&lt;/p&gt;

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

&lt;p&gt;In conclusion, despite the formidable name of &lt;em&gt;distributed tracing&lt;/em&gt;, it essentially boils down to passing data (&lt;code&gt;TraceId&lt;/code&gt;, &lt;code&gt;SpanId&lt;/code&gt;, &lt;code&gt;ParentSpanId&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;That's the way OpenTelemetry facilitates distributed tracing.&lt;/p&gt;

</description>
      <category>sre</category>
      <category>webdev</category>
      <category>microservices</category>
      <category>monitoring</category>
    </item>
    <item>
      <title>Echoed: Observable Integration Testing using OpenTelemetry on top of Jest</title>
      <dc:creator>mrasu</dc:creator>
      <pubDate>Thu, 18 Jan 2024 15:00:00 +0000</pubDate>
      <link>https://dev.to/mrasu/echoed-observable-integration-testing-with-opentelemetry-9ea</link>
      <guid>https://dev.to/mrasu/echoed-observable-integration-testing-with-opentelemetry-9ea</guid>
      <description>&lt;p&gt;Troubleshooting integration test failures can be challenging, especially when you run multiple servers.&lt;br&gt;
If you're running multiple requests in one spec, the complexity increases further.&lt;/p&gt;

&lt;p&gt;To tackle this issue, I've created a package called Echoed, integrating OpenTelemetry into Jest.&lt;br&gt;
&lt;a href="https://github.com/mrasu/echoed"&gt;https://github.com/mrasu/echoed&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'd like to get feedback for it.&lt;/p&gt;
&lt;h2&gt;
  
  
  What is Echoed?
&lt;/h2&gt;

&lt;p&gt;Echoed simplifies integration testing, aka API testing, by analyzing requests executed during testing and presenting the results in HTML format.&lt;/p&gt;

&lt;p&gt;Key Features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Efficient Debugging&lt;/strong&gt;: Easily debug failed tests by aggregating OpenTelemetry traces and logs and outputting HTML.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Coverage Measurement&lt;/strong&gt;: Measure the coverage of each service's endpoint in a microservices architecture.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Propagation Leak Detection&lt;/strong&gt;: Identify the lack of OpenTelemetry's context propagation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Span Verification&lt;/strong&gt;: Verify the content of spans, such as duration, SQL queries, and more.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compatibility&lt;/strong&gt;: No changes are required for existing tests or packages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CI-Friendly&lt;/strong&gt;: No external services are needed, making it easy to execute in CI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Jest features&lt;/strong&gt;: Since Echoed is built on top of Jest, it supports debugging and parallel execution.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Visualizing Traces
&lt;/h2&gt;

&lt;p&gt;Echoed creates HTML to visualize the traces of executed requests.&lt;/p&gt;

&lt;p&gt;The following image illustrates the trace graph generated by Echoed.&lt;br&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%2F5nvuq19qvvoy3jm9skjj.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%2F5nvuq19qvvoy3jm9skjj.png" alt="Trace Graph" width="800" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In addition to trace visualization, Echoed extends its functionality to offer coverage measurements for each service's endpoints, even when accessed internally within a microservices architecture.&lt;br&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%2Frq57tvthitq49335a0m4.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%2Frq57tvthitq49335a0m4.png" alt="Coverage Graph" width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;Installing Echoed is a straightforward process, offering two options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;New Setup:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run the command &lt;code&gt;npx echoed@latest&lt;/code&gt; in your terminal. This will generate a codebase with samples, streamlining your initial setup process.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Integration into Existing Test Suite:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Adjust Jest's configuration by modifying &lt;code&gt;jest.config.js&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add the Echoed configuration file (.echoed.yml).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more guidance, refer to the &lt;a href="https://github.com/mrasu/echoed/blob/main/README.md"&gt;README&lt;/a&gt; included with GitHub's repository.&lt;/p&gt;
&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;To demonstrate the power of Echoed, let's explore a couple of practical examples.&lt;br&gt;
The following code snippets showcase how Echoed can be seamlessly integrated into your test suites to visualize traces and ensure the correctness of your services.&lt;/p&gt;
&lt;h3&gt;
  
  
  Visualizing Traces
&lt;/h3&gt;

&lt;p&gt;Visualizing traces is a breeze with Echoed. Check out the examples below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Awesome test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;should pass&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`http://localhost:8080/api/cart`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&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;Because Echoed inspect &lt;code&gt;fetch&lt;/code&gt; automatically, you can visualize a trace for the &lt;code&gt;http://localhost:8080/api/cart&lt;/code&gt; without any special code.&lt;/p&gt;
&lt;h3&gt;
  
  
  Verifying Executed SQL
&lt;/h3&gt;

&lt;p&gt;To verify executed SQL, &lt;code&gt;waitForSpan&lt;/code&gt; function is:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Awesome test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;should create an OpenTelemetry span&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`http://localhost:8080/api/products`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Awesome Product&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&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="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;span&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;waitForSpan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;--This line!&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;oteldemo.ProductCatalogService/CreateProducts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;service.name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;productcatalogservice&lt;/span&gt;&lt;span class="dl"&gt;"&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="na"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;db.system&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;postgresql&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;db.statement&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;INSERT&lt;/span&gt; &lt;span class="nx"&gt;INTO&lt;/span&gt; &lt;span class="nx"&gt;products&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;,
&lt;/span&gt;      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;db.statement&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;stringValue&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;INSERT INTO products (name, price) VALUES ('Awesome Product', 100)&lt;/span&gt;&lt;span class="dl"&gt;"&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;This test checks for the SQL statement, &lt;code&gt;INSERT INTO...&lt;/code&gt;.&lt;br&gt;
Like this code you can verify the behavior of your services at a detailed level.&lt;/p&gt;
&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Echoed improves the experience of integration testing.&lt;br&gt;
Visualize traces, measure coverage, and verify the content of spans effortlessly.&lt;br&gt;
Check out the GitHub repository, and give it a try.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/mrasu"&gt;
        mrasu
      &lt;/a&gt; / &lt;a href="https://github.com/mrasu/echoed"&gt;
        echoed
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Observable Integration Testing using OpenTelemetry on top of Jest.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div&gt;
&lt;a rel="noopener noreferrer" href="https://github.com/mrasu/echoed/raw/main/docs/img/logo.svg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qNTXCuis--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/mrasu/echoed/raw/main/docs/img/logo.svg" alt="echoed logo" height="300"&gt;&lt;/a&gt;
&lt;h1&gt;
Echoed&lt;/h1&gt;
&lt;h4&gt;
Observable Integration Testing using OpenTelemetry on top of Jest.&lt;/h4&gt;
&lt;/div&gt;

&lt;h1&gt;
Table of contents&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/mrasu/echoed#Features"&gt;Features&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mrasu/echoed#How-Echoed-Works"&gt;How Echoed Works&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mrasu/echoed#Screenshots"&gt;Screenshots&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mrasu/echoed#Installation"&gt;Installation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/mrasu/echoed#How-to-Use"&gt;How to Use&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/mrasu/echoed#YAML"&gt;YAML&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mrasu/echoed#TypeScript"&gt;TypeScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mrasu/echoed#Analyze-Coverage"&gt;Analyze Coverage&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mrasu/echoed#Configuration"&gt;Configuration&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
Features&lt;/h1&gt;

&lt;p&gt;Echoed enhances Integration testing, aka API testing with the following features:&lt;/p&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Effortless Test Troubleshooting&lt;/strong&gt;: Quickly identify issues in failed tests by visualizing OpenTelemetry's traces and logs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;YAML Supported&lt;/strong&gt;: Write tests effortlessly using YAML and easily expand functionality through your plugins.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Coverage Analysis&lt;/strong&gt;: Gain insights into the coverage of your API endpoints based on OpenAPI or Protocol Buffers specifications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Detect Propagation Leaks&lt;/strong&gt;: Uncover spans that don't propagate OpenTelemetry's context to their children.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate Spans&lt;/strong&gt;: Validate span's fields, such as SQL or requests going outside.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CI-Friendly&lt;/strong&gt;: Integrates with CI without relying on external services.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IDE Debugging&lt;/strong&gt;: Debug your tests in your preferred IDE, leveraging Jest's built-in debugging capabilities.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code Compatibility&lt;/strong&gt;: No need to modify your existing…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/mrasu/echoed"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;I'd appreciate any feedback – whether you liked it or not!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>typescript</category>
      <category>testing</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
