<?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: Zach</title>
    <description>The latest articles on DEV Community by Zach (@za).</description>
    <link>https://dev.to/za</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%2F194981%2F9797cf64-576a-42b6-95bf-785c08178d19.png</url>
      <title>DEV Community: Zach</title>
      <link>https://dev.to/za</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/za"/>
    <language>en</language>
    <item>
      <title>Deno + OpenTelemetry</title>
      <dc:creator>Zach</dc:creator>
      <pubDate>Sat, 24 Feb 2024 00:00:00 +0000</pubDate>
      <link>https://dev.to/za/deno-opentelemetry-bj7</link>
      <guid>https://dev.to/za/deno-opentelemetry-bj7</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F846wdkg6oyo5u25gxcg6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F846wdkg6oyo5u25gxcg6.png" alt="combined deno and open telemetry logos" width="484" height="242"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The most &lt;a href="https://deno.com/blog/v2.2" rel="noopener noreferrer"&gt;recent release of Deno&lt;/a&gt; last week included a feature that I think is very exciting: it built support for Open Telemetry directly into the runtime.&lt;/p&gt;

&lt;p&gt;Deno’s an incredible platform, but the lack of observability support has made it a non-starter for anything serious in production. While logging is obviously built in, and you could use an existing metrics library like prometheus with npm specifiers for custom metrics,&lt;a href="https://github.com/DataDog/dd-trace-js/issues/1892" rel="noopener noreferrer"&gt;existing tracing libraries&lt;/a&gt;are highly coupled to Node due to differences in the way things like promises are handled by the runtime. Even Open Telemetry only supports Node and the browser. There’s been an issue tacking Deno support open for almost 4 years now, but it’s been&lt;a href="https://github.com/open-telemetry/opentelemetry-js/issues/2293#issuecomment-1700862868" rel="noopener noreferrer"&gt;slow to progress&lt;/a&gt;. This isn’t unreasonable - Node has&lt;a href="https://survey.stackoverflow.co/2024/technology#1-web-frameworks-and-technologies" rel="noopener noreferrer"&gt;orders of magnitude more users than Deno&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Open Telemetry makes a lot of sense for Deno - mostly because it’s the new-ish kid on the block, and there’s not much incentive for every vendor to put energy into supporting it. But if there’s an open protocol that all the vendors support, there’s a single API that the Deno maintainers need to implement and suddenly they support all the major vendors.&lt;/p&gt;

&lt;p&gt;There were a &lt;a href="https://github.com/deno-otel" rel="noopener noreferrer"&gt;few 3rd party attempts&lt;/a&gt; to get Open Telemetry working in Deno, but it feels like this sort of native support came out of nowhere. The first PR looks like it was opened only a couple months ago, mid November last year.&lt;/p&gt;

&lt;p&gt;I played around with the new Open Telemetry functionality, I’ll share the steps to recreate. I’m using &lt;a href="https://fresh.deno.dev/" rel="noopener noreferrer"&gt;Fresh&lt;/a&gt;, which is a web framework built for Deno, and sending the telemetry to&lt;a href="https://www.honeycomb.io/" rel="noopener noreferrer"&gt;Honeycomb&lt;/a&gt;. Sending data to other vendors may be different, some may require you to use an Open Telemetry collector if they don’t suport direct OTLP ingest.&lt;/p&gt;

&lt;p&gt;First, create a new project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;deno run -A -r https://fresh.deno.dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start the application with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OTEL\_DENO=true \
OTEL\_EXPORTER\_OTLP\_ENDPOINT='https://api.honeycomb.io' \
OTEL\_EXPORTER\_OTLP\_HEADERS='x-honeycomb-team=lkvJ6F0f7D8b9pqkR7uZ6C' \
OTEL\_SERVICE\_NAME='fresh-project' \
deno run --unstable-otel -A --watch=static/,routes/ dev.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then open the home page in a browser. Log in to Honeycomb and we should see the data showing up under a dataset named “fresh-project”, or whatever name was used for OTEL_SERVICE_NAME. We should see the traces generated by GET requests to the server have been sent to Honeycomb. This is because Deno.serve has been auto-instrumented by the runtime.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3diapdswyflngu935qh8.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3diapdswyflngu935qh8.webp" alt="screenshot of honeycomb.io showing traces generated by Deno" width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can also see logs from the server’s startup.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5477hrh2hdgbn6jr5t3a.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5477hrh2hdgbn6jr5t3a.webp" alt="screenshot of honeycomb.io showing some startup logs" width="800" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we want to recieve some telemetry from the browser, we can make a couple small updates. This isn’t technically showcasing any Deno-related features because it’s on the client side, but I think it’s nice to include.&lt;/p&gt;

&lt;p&gt;First, add a provider component to the application wrapper. It’s basically just some example code provided in the Open Telemetry documentation. We’ll also need to install some extra dependencies the new component uses.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {
  CompositePropagator,
  W3CBaggagePropagator,
  W3CTraceContextPropagator,
} from "@opentelemetry/core";
import { WebTracerProvider } from "@opentelemetry/sdk-trace-web";
import { SimpleSpanProcessor } from "@opentelemetry/sdk-trace-base";
import { registerInstrumentations } from "@opentelemetry/instrumentation";
import { getWebAutoInstrumentations } from "@opentelemetry/auto-instrumentations-web";
import { Resource } from "@opentelemetry/resources";
import { ATTR\_SERVICE\_NAME } from "@opentelemetry/semantic-conventions";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
import { ComponentChildren } from "preact";

const { ZoneContextManager } = await import("@opentelemetry/context-zone");

const exporter = new OTLPTraceExporter({
  url: "https://api.honeycomb.io/v1/traces",
  headers: {
    "x-honeycomb-team": "lkvJ6F0f7D8b9pqkR7uZ6C",
  },
});

const provider = new WebTracerProvider({
  resource: new Resource({
    [ATTR\_SERVICE\_NAME]: "fresh-project",
    "user\_agent.original": globalThis.navigator.userAgent,
  }),
  spanProcessors: [
    new SimpleSpanProcessor(exporter),
  ],
});

const contextManager = new ZoneContextManager();

provider.register({
  contextManager,
  propagator: new CompositePropagator({
    propagators: [
      new W3CBaggagePropagator(),
      new W3CTraceContextPropagator(),
    ],
  }),
});

registerInstrumentations({
  tracerProvider: provider,
  instrumentations: [
    getWebAutoInstrumentations({
      "@opentelemetry/instrumentation-fetch": {
        propagateTraceHeaderCorsUrls: /.\*/,
        clearTimingResources: true,
        applyCustomAttributesOnSpan(span) {
          span.setAttribute("app.synthetic\_request", "false");
        },
      },
    }),
  ],
});

interface Props {
  children: ComponentChildren;
}

export default function TraceProvider({ children }: Props) {
  return (
    &amp;lt;&amp;gt;{children}&amp;lt;/&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we visit Honeycomb again after reloading the page, we should see traces that look a little different (more spans). These represent the document loading.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjh9o79nitkvg0qpg9dkm.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjh9o79nitkvg0qpg9dkm.webp" alt="screenshot of honeycomb.io showing some traces with multiple spans generated by the browser" width="800" height="250"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Parameterized testing in Deno</title>
      <dc:creator>Zach</dc:creator>
      <pubDate>Tue, 21 Sep 2021 06:33:54 +0000</pubDate>
      <link>https://dev.to/za/parameterized-testing-in-deno-168i</link>
      <guid>https://dev.to/za/parameterized-testing-in-deno-168i</guid>
      <description>&lt;p&gt;I'd like to share a simple function I wrote for parameterized test in &lt;a href="//deno.land"&gt;Deno&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;One of the things I like about Deno is that the developers are building in a lot of boilerplate tooling into the runtime. This reduces a lot of the code that seems to come along by default with node projects. A mid-sized node project can easily have a dozen or so primary dependencies supporting testing, and many more transitive dependencies. &lt;/p&gt;

&lt;p&gt;Deno, on the other hand, only has one function related to testing in the runtime api (Deno.test, to register tests), and a small handful of assertions in the standard library. It's all you &lt;em&gt;really&lt;/em&gt; need, but sometimes the extras can be nice.&lt;/p&gt;

&lt;p&gt;Like parameterized tests. If you haven't used a test library that supports them, parameterized tests are basically just a syntactic sugar for running the same test case on different inputs. &lt;a href="https://jestjs.io/blog/2018/05/29/jest-23-blazing-fast-delightful-testing#jest-each"&gt;For example, Jest's .each function&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To achieve something similar in Deno, give this a try (I called it 'each' as well, for lack of a better name):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function each&amp;lt;T&amp;gt;(params: Record&amp;lt;string, T&amp;gt;, cb: (p: T) =&amp;gt; void) {
  Object.keys(params).map(title =&amp;gt; {
    Deno.test(title, () =&amp;gt; { cb(params[title]) });
  });
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Calling it looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { assertEquals } from "https://deno.land/std@0.107.0/testing/asserts.ts";
each&amp;lt;[number[], number]&amp;gt;(
  {
    "1 + 2 + 3 == 6":     [[1, 2, 3], 6],
    "-1 + -2 + -3 == -6": [[-1, -2, -3], -6],
    "1 + 1 == 2":         [[1, 1], 2],
    "10 + 9 + 8 + 7 == ": [[10, 9, 8, 7], 34],
  },
  ([vals, expected]) =&amp;gt; {
    const actual = vals.reduce((a,b) =&amp;gt; a + b);
    assertEquals(expected, actual);
  }
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hopefully this can be helpful to someone, at least until more comprehensive testing features are added to the Deno runtime. You can read some of the ongoing discussion around a new test related api &lt;a href="https://github.com/denoland/deno/discussions/10771"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>deno</category>
      <category>testing</category>
      <category>typescript</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
