<?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: jalil laaraichi</title>
    <description>The latest articles on DEV Community by jalil laaraichi (@reachjalil).</description>
    <link>https://dev.to/reachjalil</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4129146%2Fa88238a7-4923-479c-8779-3ba513d700da.jpg</url>
      <title>DEV Community: jalil laaraichi</title>
      <link>https://dev.to/reachjalil</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/reachjalil"/>
    <language>en</language>
    <item>
      <title>How we tuned TypeSafe Jev for log triage without alert storms</title>
      <dc:creator>jalil laaraichi</dc:creator>
      <pubDate>Fri, 18 Sep 2026 22:57:27 +0000</pubDate>
      <link>https://dev.to/reachjalil/how-we-tuned-typesafe-jev-for-log-triage-without-alert-storms-1ei0</link>
      <guid>https://dev.to/reachjalil/how-we-tuned-typesafe-jev-for-log-triage-without-alert-storms-1ei0</guid>
      <description>&lt;p&gt;TypeSafe Jev is a typed evaluation model available on Vercel AI Gateway. It costs 0.042 dollars per million input tokens, and output tokens are free. Because the price is low, many teams want to use it as a programmable filter on log streams, either to trigger on-call alerts or to drop routine noise before sending logs to larger models.&lt;/p&gt;

&lt;p&gt;We tested Jev on a stream of 3,000 synthetic payment and checkout logs, and on 5,000 lines from the Loghub dataset. We ran into several unexpected problems, including alert storms on normal deployments and pre-filtering pipelines that cost more money than sending raw logs directly to GPT-5.6 Luna.&lt;/p&gt;

&lt;p&gt;Here is what went wrong, what fixed it, and the code patterns that worked.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with discrete urgency labels
&lt;/h2&gt;

&lt;p&gt;In our first implementation, we asked Jev to classify each incoming log into one of three buckets: page, ticket, or ignore.&lt;/p&gt;

&lt;p&gt;This setup produced zero false alarms, but it failed to catch database replication lag. In our test data, a replica fell 47 minutes behind while the primary database continued taking writes. The application logged this event with INFO severity. Because the log level was INFO, Jev selected ticket instead of page.&lt;/p&gt;

&lt;p&gt;The model saw the danger in its probability scores. Jev assigned an alert probability between 0.24 and 0.31 to the 47 minute lag, compared to 0.11 for normal 12 second lag. The discrete choice head discarded that difference and output ticket.&lt;/p&gt;

&lt;p&gt;We tried fixing this by changing the prompt. We instructed Jev that INFO severity should not prevent an alert if customer data was at risk.&lt;/p&gt;

&lt;p&gt;That prompt change caused an alert storm. The discrete choice head became hypersensitive. It generated 189 false pages across 3,000 lines, and 122 of those false pages were completely normal deployment notifications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Thresholding probability in application code
&lt;/h2&gt;

&lt;p&gt;Prompt changes were too blunt to control the decision boundary. Instead of tuning the prompt, we moved the decision logic into our application code.&lt;/p&gt;

&lt;p&gt;We removed the three-way urgency classification. We asked Jev one boolean question: should this log page an engineer right now.&lt;/p&gt;

&lt;p&gt;Instead of relying on the boolean true or false answer, we read the continuous probability from the response object. We then set a threshold directly in JavaScript:&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createJevPager&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jevlogs&lt;/span&gt;&lt;span class="dl"&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;pager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createJevPager&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;pageAbove&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.50&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;log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;orders-db&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;severityText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INFO&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Replica lag 47m on primary still accepting writes&lt;/span&gt;&lt;span class="dl"&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;decision&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;pager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;log&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="nx"&gt;decision&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;triggerPagerDuty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;decision&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;probability&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;Setting the threshold to 0.50 in code caught all 500 incidents in the dataset, including all 57 replication lag lines. It produced zero false alarms across the 3,000 test logs.&lt;/p&gt;

&lt;p&gt;Asking a single boolean question also reduced token counts. The single question prompt cost 0.062 dollars for all 3,000 calls, compared to 0.087 dollars when asking for multiple fields.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benchmark comparison on 3,000 logs
&lt;/h2&gt;

&lt;p&gt;We compared the probability threshold against traditional severity filtering and OpenAI GPT-5.6 Luna. Luna was called with structured JSON output on the same gateway key.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Trigger method&lt;/th&gt;
&lt;th&gt;Page recall&lt;/th&gt;
&lt;th&gt;Page precision&lt;/th&gt;
&lt;th&gt;False pages&lt;/th&gt;
&lt;th&gt;INFO replica lag caught&lt;/th&gt;
&lt;th&gt;Gateway spend&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ERROR severity filter&lt;/td&gt;
&lt;td&gt;49.2 percent&lt;/td&gt;
&lt;td&gt;33.0 percent&lt;/td&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;td&gt;0 of 57&lt;/td&gt;
&lt;td&gt;0.00 dollars&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jev version 1 with discrete urgency&lt;/td&gt;
&lt;td&gt;88.6 percent&lt;/td&gt;
&lt;td&gt;100.0 percent&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0 of 57&lt;/td&gt;
&lt;td&gt;0.072 dollars&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jev version 2 with loosened prompt&lt;/td&gt;
&lt;td&gt;100.0 percent&lt;/td&gt;
&lt;td&gt;72.6 percent&lt;/td&gt;
&lt;td&gt;189&lt;/td&gt;
&lt;td&gt;57 of 57&lt;/td&gt;
&lt;td&gt;0.087 dollars&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jev version 3 with probability 0.50&lt;/td&gt;
&lt;td&gt;100.0 percent&lt;/td&gt;
&lt;td&gt;100.0 percent&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;57 of 57&lt;/td&gt;
&lt;td&gt;0.062 dollars&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-5.6 Luna structured output&lt;/td&gt;
&lt;td&gt;96.2 percent&lt;/td&gt;
&lt;td&gt;100.0 percent&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;46 of 57&lt;/td&gt;
&lt;td&gt;0.320 dollars&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Traditional log levels failed as an on-call trigger. Paging on ERROR caught less than half of the incidents and woke up engineers for 500 expected validation errors.&lt;/p&gt;

&lt;p&gt;Luna caught 46 of the 57 replication lag incidents, but Azure content filtering dropped 130 log lines that contained search injection strings. Jev processed all lines without errors.&lt;/p&gt;

&lt;h2&gt;
  
  
  When pre-filtering logs increases your bill
&lt;/h2&gt;

&lt;p&gt;Many developers consider placing Jev in front of a larger language model to drop routine logs and reduce total cost.&lt;/p&gt;

&lt;p&gt;The financial outcome depends on the percentage of logs you drop. Consider a stream of one million logs.&lt;/p&gt;

&lt;p&gt;If the downstream model is GPT-5.6 Luna at 0.20 dollars per million input tokens and 1.20 dollars per million output tokens, processing 1,000,000 logs with Luna costs 120 dollars.&lt;/p&gt;

&lt;p&gt;Jev uses roughly 537 input tokens per log, which costs 22 dollars and 55 cents per million logs.&lt;/p&gt;

&lt;p&gt;To break even, Jev must drop at least 18.8 percent of the log stream.&lt;/p&gt;

&lt;p&gt;On the Loghub HDFS dataset, Jev was conservative. Its default score kept 99.16 percent of lines, dropping only 0.84 percent. Adding Jev as a pre-filter increased the total bill from 120 dollars to 142 dollars.&lt;/p&gt;

&lt;p&gt;If your filter criteria only drop a small fraction of lines, adding a triage model acts as a surcharge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Caching repeated log templates
&lt;/h2&gt;

&lt;p&gt;System logs consist mostly of static templates with changing IDs, IP addresses, and timestamps.&lt;/p&gt;

&lt;p&gt;Before calling Jev, we sanitize the log body by replacing IP addresses and block IDs with fixed strings. We then compute a SHA-256 hash of the sanitized string and check an in-memory cache with a five minute expiration:&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createHash&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node:crypto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;sanitizeLog&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="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[IP]&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="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/blk_&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;-0-9&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[BLOCK]&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getProbability&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="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&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;sanitized&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sanitizeLog&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sha256&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sanitized&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hex&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hash&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="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&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;p&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;callJev&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sanitized&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;p&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;On our 2,500-line HDFS sample, 2,412 lines matched an earlier template. This in-memory cache reduced model calls from 2,500 to 88, cutting token consumption from 1,350,308 to 48,019 tokens.&lt;/p&gt;

&lt;h2&gt;
  
  
  Production rules for log evaluation
&lt;/h2&gt;

&lt;p&gt;First, protect errors locally. If a log arrives with FATAL or CRITICAL severity, route it immediately in code. Do not spend model tokens on records that already require human review.&lt;/p&gt;

&lt;p&gt;Second, avoid multi-field schemas. Ask one boolean question to keep token counts low and responses fast.&lt;/p&gt;

&lt;p&gt;Third, read the continuous probability. Do not let the model choose discrete urgency buckets. Enforce your cutoffs in application code.&lt;/p&gt;

&lt;p&gt;Fourth, separate your archive pipeline from your triage pipeline. Send all raw logs to your storage backend through an independent OpenTelemetry processor so model timeouts never drop audit records.&lt;/p&gt;

&lt;p&gt;The code, test datasets, and interactive explorer are available on Hugging Face under reachjalil/jev-luna-pagerduty-trigger.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>observability</category>
      <category>typescript</category>
      <category>ai</category>
    </item>
    <item>
      <title>let Jev score OpenTelemetry logs before a bigger LLM sees them</title>
      <dc:creator>jalil laaraichi</dc:creator>
      <pubDate>Thu, 17 Sep 2026 06:07:50 +0000</pubDate>
      <link>https://dev.to/reachjalil/let-jev-score-opentelemetry-logs-before-a-bigger-llm-sees-them-196d</link>
      <guid>https://dev.to/reachjalil/let-jev-score-opentelemetry-logs-before-a-bigger-llm-sees-them-196d</guid>
      <description>&lt;p&gt;Health checks. Cache hits. A payment failure hiding in the middle. If every OpenTelemetry log goes into a reasoning model, you pay for noise before the investigation starts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Jev Logs&lt;/strong&gt; is a small open-source layer that puts &lt;a href="https://typesafe.ai/" rel="noopener noreferrer"&gt;TypeSafe’s Jev&lt;/a&gt; in front of those logs. Jev makes the first decision: how useful is this record, how urgent is it, and does it deserve a more expensive model?&lt;/p&gt;

&lt;p&gt;I wrote it. MIT licensed. Independent not a TypeSafe, Vercel, or OpenTelemetry product.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/reachjalil" rel="noopener noreferrer"&gt;
        reachjalil
      &lt;/a&gt; / &lt;a href="https://github.com/reachjalil/jevlogs" rel="noopener noreferrer"&gt;
        jevlogs
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Open-source Jev log triage for OpenTelemetry. Score the signal before expensive LLM analysis.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;p&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://raw.githubusercontent.com/reachjalil/jevlogs/main/docs/assets/readme-banner.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Freachjalil%2Fjevlogs%2Fmain%2Fdocs%2Fassets%2Freadme-banner.png" alt="Jev Logs — Keep your logs. Spend on the signal. A relaxed robot in blue headphones sorts log records into background and signal." width="100%"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Jev Logs&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;
  &lt;strong&gt;A little intelligence between your logs and your LLM bill.&lt;/strong&gt;&lt;br&gt;
  Score, prioritize, and route OpenTelemetry logs with Jev. Keep the signal. Keep your stack
&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://www.npmjs.com/package/jevlogs" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/c467a01d0153402bebe83c891848de1a9bc16c53e2ded4427b9ff4466034f964/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f762f6a65766c6f67733f7374796c653d666c61742d73717561726526636f6c6f723d323434386666" alt="npm version"&gt;&lt;/a&gt;
  &lt;a href="https://github.com/reachjalil/jevlogs/actions/workflows/ci.yml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/reachjalil/jevlogs/actions/workflows/ci.yml/badge.svg?branch=main" alt="CI status"&gt;&lt;/a&gt;
  &lt;a href="https://github.com/reachjalil/jevlogs/blob/main/LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f5376dc1d031dd0662b38612c9a11df92351f5db5da74e7827bd544b6d201ec1/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d3234343866663f7374796c653d666c61742d737175617265" alt="MIT license"&gt;&lt;/a&gt;
  &lt;a href="https://nodejs.org/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/67a9385e8b29bb33c2076525150d692af77d46deec7a83f82f23127b38553d7a/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6e6f64652d25453225383925413532322d3131313331623f7374796c653d666c61742d737175617265" alt="Node.js 22 or later"&gt;&lt;/a&gt;
  &lt;a href="https://github.com/reachjalil/jevlogs#project-status" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f804ccb45dcb02ec5dfc9b93932a7cc7fddeb67a4d8c74c95036d81585523836/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7374617475732d707265766965772d3862356366363f7374796c653d666c61742d737175617265" alt="Status: preview"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://jevlogs.com" rel="nofollow noopener noreferrer"&gt;&lt;strong&gt;Website&lt;/strong&gt;&lt;/a&gt; ·
  &lt;a href="https://jevlogs.com/guide/" rel="nofollow noopener noreferrer"&gt;&lt;strong&gt;Guide&lt;/strong&gt;&lt;/a&gt; ·
  &lt;a href="https://jevlogs.com/llms.txt" rel="nofollow noopener noreferrer"&gt;&lt;strong&gt;llms.txt&lt;/strong&gt;&lt;/a&gt; ·
  &lt;a href="https://www.npmjs.com/package/jevlogs" rel="nofollow noopener noreferrer"&gt;&lt;strong&gt;npm&lt;/strong&gt;&lt;/a&gt; ·
  &lt;a href="https://github.com/reachjalil/jevlogs/issues" rel="noopener noreferrer"&gt;&lt;strong&gt;Feedback&lt;/strong&gt;&lt;/a&gt;
&lt;/p&gt;




&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Meet your log filter’s smarter friend&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;Health checks. Cache hits. A payment failure hiding in the middle. Sending every event to a reasoning model adds cost before the investigation even starts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Jev Logs makes the first decision:&lt;/strong&gt; how useful is this log, how urgent is it, and does it deserve deeper analysis? It uses &lt;a href="https://typesafe.ai/" rel="nofollow noopener noreferrer"&gt;TypeSafe’s Jev&lt;/a&gt; through the Vercel AI SDK, with a small TypeScript API and an OpenTelemetry exporter wrapper.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;&lt;div class="table-wrapper-paragraph"&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;table&gt;

&lt;thead&gt;

&lt;tr&gt;

&lt;th&gt;A small layer&lt;/th&gt;

&lt;th&gt;What you get&lt;/th&gt;

&lt;/tr&gt;

&lt;/thead&gt;

&lt;tbody&gt;

&lt;tr&gt;

&lt;td&gt;&lt;strong&gt;Score the signal&lt;/strong&gt;&lt;/td&gt;

&lt;td&gt;A 0–100 diagnostic-value score, priority, and actionable probability.&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;&lt;strong&gt;Keep your pipeline&lt;/strong&gt;&lt;/td&gt;

&lt;td&gt;Wrap your existing exporter; preserve resource, scope, timestamps, and trace context.&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;&lt;strong&gt;Start with visibility&lt;/strong&gt;&lt;/td&gt;

&lt;td&gt;Annotation mode keeps every record and attaches &lt;code&gt;jev.*&lt;/code&gt; attributes.&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;&lt;strong&gt;Spend&lt;/strong&gt;&lt;/td&gt;

&lt;/tr&gt;

&lt;/tbody&gt;

&lt;/table&gt;&lt;/div&gt;…&lt;p&gt;&lt;/p&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/reachjalil/jevlogs" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;h2&gt;
  
  
  What Jev actually returns
&lt;/h2&gt;

&lt;p&gt;Jev is built for structured choices, not paragraphs. For each log, Jev Logs asks it for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a &lt;strong&gt;diagnostic value&lt;/strong&gt; (0–100)&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;priority&lt;/strong&gt; (&lt;code&gt;critical&lt;/code&gt;, &lt;code&gt;high&lt;/code&gt;, &lt;code&gt;normal&lt;/code&gt;, &lt;code&gt;low&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;an &lt;strong&gt;actionable probability&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;route&lt;/strong&gt;: &lt;code&gt;analyze&lt;/code&gt; or &lt;code&gt;retain&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your archive still gets every record. The analysis branch only needs the ones Jev (or a rule, or a conservative fallback) says are worth it.&lt;/p&gt;

&lt;p&gt;A log may skip deeper analysis only when &lt;strong&gt;all three&lt;/strong&gt; are true: priority is &lt;code&gt;low&lt;/code&gt;, value is 25 or below, and actionable probability is under &lt;code&gt;0.1&lt;/code&gt;. Errors, &lt;code&gt;jev.protected&lt;/code&gt; records, timeouts, and provider failures stay eligible. Nothing in the SDK deletes your logs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try Jev Logs in one command
&lt;/h2&gt;

&lt;p&gt;Offline demo. No key. No network.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx jevlogs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   0 / 100  low      RETAIN   GET /health returned 200 in 2ms
  25 / 100  low      RETAIN   Cache hit for product:482
 100 / 100  critical ANALYZE  Payment capture failed after three retries
  75 / 100  high     ANALYZE  Database connection pool at 94% capacity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That walkthrough uses fixed answers so you can see the shape. It does not call Jev.&lt;/p&gt;

&lt;p&gt;Real Jev, still on your machine:&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;AI_GATEWAY_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your-vercel-ai-gateway-key

npx jevlogs &lt;span class="nt"&gt;--live&lt;/span&gt; &lt;span class="nt"&gt;--sample&lt;/span&gt;
npx jevlogs &lt;span class="nt"&gt;--live&lt;/span&gt; &lt;span class="nt"&gt;--file&lt;/span&gt; ./app.log &lt;span class="nt"&gt;--limit&lt;/span&gt; 20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;--live&lt;/code&gt; alone starts a local OTLP HTTP/JSON receiver on &lt;code&gt;http://127.0.0.1:4318/v1/logs&lt;/code&gt;. Point your app at it; Jev Logs prints one JSON decision per record and can forward annotated batches to the collector you already run. Node.js 22+.&lt;/p&gt;

&lt;h2&gt;
  
  
  Score a log from TypeScript
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;jevlogs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createJevLogs&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;jevlogs&lt;/span&gt;&lt;span class="dl"&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;jev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createJevLogs&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;decision&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;jev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;triage&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Database connection pool at 94% capacity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;severityText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;WARN&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;decision&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// value · priority · route · actionableProbability · reason&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Skip health checks without spending a Jev call:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;jev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createJevLogs&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;:&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;health&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;match&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;^GET /health&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;route&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;retain&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Already on OpenTelemetry?
&lt;/h2&gt;

&lt;p&gt;Wrap the exporter you have. Annotation mode keeps every log and attaches &lt;code&gt;jev.*&lt;/code&gt; attributes.&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;LoggerProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;BatchLogRecordProcessor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;ConsoleLogRecordExporter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@opentelemetry/sdk-logs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;JevLogExporter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;jevlogs&lt;/span&gt;&lt;span class="dl"&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;provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LoggerProvider&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;processors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BatchLogRecordProcessor&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;exporter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;JevLogExporter&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;exporter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ConsoleLogRecordExporter&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;annotate&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="na"&gt;maxExportBatchSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;16&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep that archive processor. Add a second exporter with &lt;code&gt;mode: "analysis-only"&lt;/code&gt; when you actually want to drop low-value records from the LLM path. &lt;strong&gt;Annotation alone does not cut the bill&lt;/strong&gt; — the downstream pipeline has to honor &lt;code&gt;route&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Jev, not “another LLM pass”
&lt;/h2&gt;

&lt;p&gt;A second giant completion per log is the thing this is trying to avoid. Jev’s published rate is cheap structured evaluation (TypeSafe lists &lt;strong&gt;$0.042/M input&lt;/strong&gt;, free output). You pay Jev for a small decision, then pay GPT-class analysis only for the selected slice.&lt;/p&gt;

&lt;p&gt;The README has an illustrative table: 1M logs/month, if 10% still need analysis, a &lt;strong&gt;$1,000&lt;/strong&gt; GPT-4.1-style bill models down to about &lt;strong&gt;$129&lt;/strong&gt; including Jev triage. That is &lt;strong&gt;not&lt;/strong&gt; a measured production result. Measure incident recall on &lt;em&gt;your&lt;/em&gt; logs before you filter.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this is not
&lt;/h2&gt;

&lt;p&gt;No hosted dashboard. No log storage. No Collector plugin. No root-cause write-up. Preview software: &lt;code&gt;jevlogs&lt;/code&gt; on npm, TypeScript first, CI on the repo. Jev itself is a hosted model via Vercel AI Gateway; this repo is the &lt;strong&gt;integration&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/reachjalil/jevlogs" rel="noopener noreferrer"&gt;reachjalil/jevlogs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Guide: &lt;a href="https://jevlogs.com/guide/" rel="noopener noreferrer"&gt;jevlogs.com/guide&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;npm: &lt;a href="https://www.npmjs.com/package/jevlogs" rel="noopener noreferrer"&gt;&lt;code&gt;jevlogs&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you try it, I want feedback on the Jev scoring/routing shape and whether wrapping an exporter is the right split vs the local receiver. Issues with sanitized examples are welcome. &lt;/p&gt;

</description>
      <category>typescript</category>
      <category>opentelemetry</category>
      <category>opensource</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
