<?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: Rishi Kumar</title>
    <description>The latest articles on DEV Community by Rishi Kumar (@mrrishimeena).</description>
    <link>https://dev.to/mrrishimeena</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%2F978918%2F63c5794e-13f2-4457-98ce-2f0388bc6ebf.jpeg</url>
      <title>DEV Community: Rishi Kumar</title>
      <link>https://dev.to/mrrishimeena</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mrrishimeena"/>
    <language>en</language>
    <item>
      <title>Breakdown: Who is Responsible?</title>
      <dc:creator>Rishi Kumar</dc:creator>
      <pubDate>Wed, 24 Dec 2025 12:35:28 +0000</pubDate>
      <link>https://dev.to/mrrishimeena/breakdown-who-is-responsible-4ghn</link>
      <guid>https://dev.to/mrrishimeena/breakdown-who-is-responsible-4ghn</guid>
      <description>&lt;p&gt;In the vast majority of commercial system designs (web apps, e-commerce, banking, SaaS), the hierarchy of "slowness" is almost always the same.&lt;/p&gt;

&lt;p&gt;For a typical application, the ranking of importance (and performance bottleneck) looks like this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Database Queries (The bottleneck)&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;2. Network Calls (The delay)&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;3. Code Algorithms (The easy part)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here is the breakdown of why, including the estimated impact percentages for a standard web application.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Breakdown: Who is Responsible?
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Database Queries (~60% of Performance Issues)
&lt;/h4&gt;

&lt;p&gt;In 9 out of 10 system design interviews (and real-world outages), the database is the first thing to break.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Why:&lt;/strong&gt; Reading data from a hard drive (Disk I/O) is physically slow. Even with SSDs, searching through millions of rows, joining tables, and waiting for "locks" takes millions of CPU cycles.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Cost:&lt;/strong&gt; A bad SQL query can freeze a system for &lt;strong&gt;seconds&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;System Design Fix:&lt;/strong&gt; This is why we use &lt;strong&gt;Caching (Redis/Memcached)&lt;/strong&gt;. We try desperately to avoid hitting the database.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  2. Network Calls (~30% of Performance Issues)
&lt;/h4&gt;

&lt;p&gt;This is the time it takes for data to travel from Server A to Server B (latency).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Why:&lt;/strong&gt; Even if your code is instant, the speed of light is a limit. If your app has "Microservices" where Service A calls Service B, which calls Service C, you are simply waiting for the data to travel wires.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Cost:&lt;/strong&gt; A network call usually takes &lt;strong&gt;milliseconds&lt;/strong&gt; (ms). In CPU time, 1ms is an eternity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;System Design Fix:&lt;/strong&gt; This is why we use &lt;strong&gt;Batching&lt;/strong&gt; (sending 100 items in 1 request instead of 100 requests) and &lt;strong&gt;CDNs&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  3. Algorithms / Code Logic (~10% of Performance Issues)
&lt;/h4&gt;

&lt;p&gt;Unless you are doing AI, Video Processing, or Crypto Mining, your algorithm is rarely the problem.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Why:&lt;/strong&gt; Modern CPUs can do &lt;strong&gt;billions&lt;/strong&gt; of calculations per second. A loop that iterates 10,000 times to sum a shopping cart takes &lt;em&gt;microseconds&lt;/em&gt; (0.000001 seconds).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Cost:&lt;/strong&gt; Negligible in comparison to waiting for a database.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;System Design Fix:&lt;/strong&gt; Keep code clean, but don't obsess over micro-optimizations. Focus on readability.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  The "Scale of Latency" (Why Algo loses)
&lt;/h3&gt;

&lt;p&gt;To understand why Algorithms matter so little compared to Network/DB, look at the time scale differences.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Let's imagine &lt;strong&gt;1 CPU Cycle = 1 Second&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Actual Time&lt;/th&gt;
&lt;th&gt;Relative Time (If 1 cycle = 1 sec)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Algo:&lt;/strong&gt; Simple Loop / Variable access&lt;/td&gt;
&lt;td&gt;~1 nanosecond&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1 second&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Network:&lt;/strong&gt; Sending 2KB data over 1Gbps&lt;/td&gt;
&lt;td&gt;~20,000 ns&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;5.5 hours&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Network:&lt;/strong&gt; Packet Round Trip (Ping)&lt;/td&gt;
&lt;td&gt;~150,000 ns&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.7 days&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Disk/DB:&lt;/strong&gt; Reading from SSD&lt;/td&gt;
&lt;td&gt;~1,000,000 ns&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;11.5 days&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Network:&lt;/strong&gt; Packet sent from US to Europe&lt;/td&gt;
&lt;td&gt;~150,000,000 ns&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4.8 years&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Conclusion:&lt;/strong&gt; Optimizing your code to save 5 CPU cycles is useless if your database query takes "11 days" (relative time) to return.&lt;/p&gt;

&lt;h3&gt;
  
  
  When does the Algorithm become #1?
&lt;/h3&gt;

&lt;p&gt;There are specific cases where the Algorithm becomes the most important factor (80%+ impact):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Video Compression/Streaming:&lt;/strong&gt; (Netflix/YouTube encoding) - Heavy CPU math.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High-Frequency Trading:&lt;/strong&gt; (Stock markets) - Every nanosecond counts; network is optimized via hardware, so code speed wins.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Encryption/Hashing:&lt;/strong&gt; (Blockchain/Crypto) - Pure mathematical processing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI/ML Inference:&lt;/strong&gt; Running neural networks is pure matrix multiplication.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;For a standard company system (like an e-commerce store or social network):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Database (60%):&lt;/strong&gt; Optimize your SQL, add Indexes, use Redis.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Network (30%):&lt;/strong&gt; Reduce the number of calls (Chatty I/O), keep servers close to users.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Algo (10%):&lt;/strong&gt; Just avoid obvious mistakes (like nested loops on massive arrays).&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>architecture</category>
      <category>startup</category>
      <category>algorithms</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Ultimate Logging Guide for Node.js, Bun, and Next.js SSR in 2025</title>
      <dc:creator>Rishi Kumar</dc:creator>
      <pubDate>Tue, 22 Apr 2025 10:16:38 +0000</pubDate>
      <link>https://dev.to/mrrishimeena/modern-nodejs-logger-is-an-npm-install-away-2ne0</link>
      <guid>https://dev.to/mrrishimeena/modern-nodejs-logger-is-an-npm-install-away-2ne0</guid>
      <description>&lt;p&gt;If you’ve been building &lt;a href="https://nodejs.org/en" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt; apps for a while, you’ve probably used &lt;a href="https://github.com/winstonjs/winston" rel="noopener noreferrer"&gt;Winston&lt;/a&gt;, &lt;a href="https://github.com/pinojs/pino" rel="noopener noreferrer"&gt;Pino&lt;/a&gt;, or maybe &lt;a href="https://github.com/trentm/node-bunyan" rel="noopener noreferrer"&gt;Bunyan&lt;/a&gt; for logging. And they’ve served us well — structured logs, log levels, file transport — all good stuff.&lt;/p&gt;

&lt;p&gt;But here's the thing: &lt;strong&gt;logs alone aren't enough anymore.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Modern applications need more than just lines in the terminal or log files. You need to &lt;strong&gt;see logs in a dashboard, filter them, search by word, errors with meta details, get alerts&lt;/strong&gt;, and sometimes even dig into logs from multiple environments — &lt;strong&gt;local, staging, prod&lt;/strong&gt; — without relying on a third-party cloud provider.&lt;/p&gt;

&lt;p&gt;And that’s exactly why &lt;strong&gt;&lt;a href="https://github.com/errsole/errsole.js" rel="noopener noreferrer"&gt;Errsole&lt;/a&gt; exists&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It’s an open-source logging system built specifically for Node.js. It’s not just a logger — it’s a complete log management tool, with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A web-based log viewer&lt;/li&gt;
&lt;li&gt;Alerts (email, &lt;a href="https://slack.com/" rel="noopener noreferrer"&gt;Slack&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Support for structured logging, metadata, and JSON payloads&lt;/li&gt;
&lt;li&gt;Built-in support for &lt;a href="https://expressjs.com/" rel="noopener noreferrer"&gt;Express&lt;/a&gt;, &lt;a href="https://fastify.dev/" rel="noopener noreferrer"&gt;Fastify&lt;/a&gt;, &lt;a href="https://nestjs.com/" rel="noopener noreferrer"&gt;NestJS&lt;/a&gt;, &lt;a href="https://koajs.com/" rel="noopener noreferrer"&gt;Koa&lt;/a&gt;, &lt;a href="https://hapi.dev/" rel="noopener noreferrer"&gt;Hapi&lt;/a&gt;, &lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;Next.js (SSR)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Storage flexibility (SQLite, MySQL, Postgres, MongoDB)&lt;/li&gt;
&lt;li&gt;Production-grade performance that beats &lt;a href="https://www.elastic.co/" rel="noopener noreferrer"&gt;Elasticsearch&lt;/a&gt; and Cloud loggers by 70,000–90,000 RPM&lt;/li&gt;
&lt;li&gt;All self-hosted, no vendor lock-in&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s break this down properly and explain why Errsole is different than every other Node.js logger — and why it might be the only logging tool you’ll need.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Built-in Log Viewer That Runs in Your App
&lt;/h2&gt;

&lt;p&gt;With Pino or Winston, you get log lines. If you want to view them visually, you have to set up something like Kibana, Grafana Loki, or a third-party tool like Better Stack or Logtail. That takes time, config, and often... monthly bills.&lt;/p&gt;

&lt;p&gt;With Errsole, the log viewer is part of the package.&lt;/p&gt;

&lt;p&gt;It runs as a lightweight web dashboard (by default on &lt;em&gt;port 8001&lt;/em&gt;), where you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Search logs by keyword, user ID, path, or any custom field&lt;/li&gt;
&lt;li&gt;Filter logs by level (error, warn, debug, info, alert)&lt;/li&gt;
&lt;li&gt;See metadata like HTTP headers, DB queries, request bodies&lt;/li&gt;
&lt;li&gt;View logs in full-screen JSON mode&lt;/li&gt;
&lt;li&gt;Inspect logs across environments and apps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And it’s super easy to embed. Just add the Express proxy middleware and you can serve the log viewer at /errsole inside your own app — no need to open ports or run extra containers.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Instant Setup with Built-in Console Capture
&lt;/h2&gt;

&lt;p&gt;Errsole works out of the box. As soon as you call errsole.initialize(), it starts capturing all logs, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;console.log, console.warn, console.error&lt;/li&gt;
&lt;li&gt;Uncaught exceptions&lt;/li&gt;
&lt;li&gt;Unhandled rejections&lt;/li&gt;
&lt;li&gt;Stack traces&lt;/li&gt;
&lt;li&gt;Errors thrown inside async functions or routes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No need to rewrite your existing log statements or wrap everything in custom logic. Errsole handles it all for you.&lt;/p&gt;

&lt;p&gt;You can also disable console output, or configure which log levels to capture using collectLogs option in its config.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Blazing Fast Performance (Benchmarks Don't Lie)
&lt;/h2&gt;

&lt;p&gt;Let’s talk real numbers.&lt;/p&gt;

&lt;p&gt;When benchmarking Errsole vs popular setups like Pino + Elasticsearch or Winston + CloudWatch, the difference was massive.&lt;/p&gt;

&lt;p&gt;In tests using AWS EC2 instances and a simple Node.js app under K6 load testing, &lt;strong&gt;Errsole consistently handled 70,000–90,000 more requests per minute than Elasticsearch-based loggers&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;p&gt;Because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Elasticsearch, CloudWatch, and Better Stack&lt;/strong&gt; all use HTTP. Logs are sent over the network — which adds latency, risk of log loss, and slowdowns under load.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Errsole writes to local databases&lt;/strong&gt;, like SQLite, MySQL, MongoDB, or Postgres. That’s faster, more reliable, and 100% under your control.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  4. Powerful Advanced Logging Features
&lt;/h2&gt;

&lt;p&gt;Errsole isn’t just about catching logs — it helps you understand them deeply.&lt;/p&gt;

&lt;p&gt;It supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Log Levels&lt;/strong&gt;: log, info, warn, error, alert, debug&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alerts&lt;/strong&gt;: Send critical logs to Slack or Email with errsole.alert()&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Structured Logs&lt;/strong&gt;: Attach metadata (like req.body, query params, user session info)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JSON-friendly view&lt;/strong&gt;: Inspect logs in a clean, collapsible format&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Search + Filter UI&lt;/strong&gt;: Find logs by route, level, words, or custom tags&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  5. Storage Options for Every Use Case
&lt;/h2&gt;

&lt;p&gt;Errsole doesn’t force you into one database or logging stack. You choose how and where to store your logs.&lt;/p&gt;

&lt;p&gt;It supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SQLite&lt;/strong&gt; for local development, testing, or small apps&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MySQL&lt;/strong&gt; for shared logs in production APIs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PostgreSQL&lt;/strong&gt; for scalable, transactional logging&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MongoDB&lt;/strong&gt; for flexible, schema-less logs and large-scale data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;_You can even run multiple apps logging into the same DB, using &lt;strong&gt;tablePrefix&lt;/strong&gt; or &lt;strong&gt;collectionPrefix&lt;/strong&gt; to separate logs by app name.&lt;/p&gt;

&lt;h2&gt;
  
  
  _
&lt;/h2&gt;

&lt;h2&gt;
  
  
  6. Runs Anywhere — &lt;strong&gt;Local, Server, Docker, Cloud&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Whether you’re developing locally, deploying to EC2, running containers, or using serverless platforms, Errsole fits right in.&lt;/p&gt;

&lt;p&gt;You can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run it as a standalone app with its own viewer UI&lt;/li&gt;
&lt;li&gt;Mount the dashboard inside your main app at any route&lt;/li&gt;
&lt;li&gt;Use it in dev, staging, or prod — with separate DBs or shared ones&lt;/li&gt;
&lt;li&gt;Use appName, environmentName, serverName to organize logs by source&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  7. Works with Your Favorite Frameworks
&lt;/h2&gt;

&lt;p&gt;Errsole integrates smoothly with popular Node.js frameworks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Express&lt;/strong&gt; (zero-config)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fastify&lt;/strong&gt; (full guide available)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NestJS&lt;/strong&gt; (supports interceptors, services, DI, etc.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Next.js SSR&lt;/strong&gt; apps (server-side logging with SQLite or MySQL)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It even works as a transport for Winston via winston-errsole, so you can upgrade your existing logger setup without a rewrite.&lt;/p&gt;




&lt;h2&gt;
  
  
  8. Safer Than Remote Logging
&lt;/h2&gt;

&lt;p&gt;Let’s be honest — cloud loggers are fast to set up, but they come with risks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Privacy issues&lt;/strong&gt;: Your logs go to someone else’s server&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Downtime risk&lt;/strong&gt;: If the logging service goes down, your logs vanish&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;App crashes&lt;/strong&gt;: Under high load, HTTP log calls can block or fail&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High cost&lt;/strong&gt;: You’ll pay per GB or per log line as you scale&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With Errsole, none of that happens. Your logs are on your infra, you pay &lt;strong&gt;$0/month&lt;/strong&gt;, and your app stays safe — even under pressure.&lt;/p&gt;




&lt;h2&gt;
  
  
  9. Real-World Proof &amp;amp; Developer Stories
&lt;/h2&gt;

&lt;p&gt;Developers have already shared their stories of switching to Errsole:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One team saw 60% throughput improvement after replacing Better Stack with Errsole&lt;/li&gt;
&lt;li&gt;Another dev caught an error that almost wiped their app’s production data — and Errsole helped them debug it in seconds&lt;/li&gt;
&lt;li&gt;Multiple teams use Errsole daily in Fastify, Next.js, and NestJS apps running at scale&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  10. Open Source, Free Forever
&lt;/h2&gt;

&lt;p&gt;Errsole is fully open-source, with permissive licensing, and runs under your full control. You can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fork it&lt;/li&gt;
&lt;li&gt;Self-host it&lt;/li&gt;
&lt;li&gt;Contribute to it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No API limits. No tracking. No hidden costs. Just logs you control, in a viewer you own.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Winston and Pino will give you log lines. Cloud loggers give you dashboards — for a price. But Errsole gives you the best of both worlds:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Easy to set up&lt;/li&gt;
&lt;li&gt;Fast to scale&lt;/li&gt;
&lt;li&gt;Beautiful to view&lt;/li&gt;
&lt;li&gt;Safe for production&lt;/li&gt;
&lt;li&gt;100% free and self-hosted&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Whether you’re a solo dev building side projects, or a team deploying production microservices, Errsole is the logging tool you didn’t know you needed.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Ready to get started?&lt;br&gt;
👉 npm install errsole&lt;br&gt;
👉 Visit: &lt;a href="https://github.com/errsole/errsole.js" rel="noopener noreferrer"&gt;https://github.com/errsole/errsole.js&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>node</category>
      <category>nextjs</category>
      <category>bunjs</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Errsole Live on Product Hunt</title>
      <dc:creator>Rishi Kumar</dc:creator>
      <pubDate>Wed, 16 Apr 2025 17:21:57 +0000</pubDate>
      <link>https://dev.to/mrrishimeena/errsole-live-on-product-hunt-84g</link>
      <guid>https://dev.to/mrrishimeena/errsole-live-on-product-hunt-84g</guid>
      <description>&lt;p&gt;Hi, we've just launched a free, open-source Node.js logger for developers on Product Hunt!&lt;/p&gt;

&lt;p&gt;If you find it interesting, support us, your support would mean a lot.&lt;/p&gt;

&lt;p&gt;Link: &lt;a href="https://www.producthunt.com/posts/errsole" rel="noopener noreferrer"&gt;https://www.producthunt.com/posts/errsole&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Would also be lovely if your team gets a chance to check it out too&lt;/p&gt;

</description>
      <category>node</category>
      <category>opensource</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Worker Threads in Node.js and Their Impact on Logging Performance</title>
      <dc:creator>Rishi Kumar</dc:creator>
      <pubDate>Tue, 25 Feb 2025 11:50:23 +0000</pubDate>
      <link>https://dev.to/mrrishimeena/worker-threads-in-nodejs-and-their-impact-on-logging-performance-315h</link>
      <guid>https://dev.to/mrrishimeena/worker-threads-in-nodejs-and-their-impact-on-logging-performance-315h</guid>
      <description>&lt;p&gt;Node.js is known for its non-blocking, event-driven architecture that makes it efficient for handling asynchronous operations. However, when it comes to CPU-bound tasks, the single-threaded nature of Node.js can become a bottleneck. This is where &lt;strong&gt;worker threads&lt;/strong&gt; come into play. They allow developers to offload CPU-intensive tasks from the main event loop to separate threads within the same process.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Are Worker Threads?
&lt;/h3&gt;

&lt;p&gt;Worker threads in Node.js enable parallelism by running JavaScript code concurrently. Instead of executing everything on the main thread—which could block incoming requests and slow down performance—worker threads let you perform heavy computations in the background. This design helps keep the main event loop free to handle I/O operations and respond to client requests.&lt;/p&gt;




&lt;h3&gt;
  
  
  How Worker Threads Affect System Performance
&lt;/h3&gt;

&lt;p&gt;Worker threads offer significant benefits on multi-core systems where &lt;strong&gt;true parallelism&lt;/strong&gt; can be achieved. When the operating system distributes the load across multiple cores, the main thread can focus on handling I/O-bound tasks, while worker threads manage CPU-intensive operations.&lt;/p&gt;

&lt;h4&gt;
  
  
  On Single-Core Systems
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;No True Parallelism:&lt;/strong&gt; With only one core, both the main thread and any worker threads must share the same CPU time. This means that the tasks are interleaved rather than executed concurrently.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Overhead of Context Switching:&lt;/strong&gt; Offloading work to a worker thread introduces overhead due to inter-thread communication and context switching. On a single-core machine, these overheads can diminish or even negate the benefits of offloading tasks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scheduling Delays:&lt;/strong&gt; The operating system must alternate between executing the main thread and the worker thread, potentially causing delays under heavy computational or logging loads.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h4&gt;
  
  
  On Multi-Core Systems Fully Occupied by Node.js Processes
&lt;/h4&gt;

&lt;p&gt;Even on multi-core machines, if all cores are dedicated to running Node.js processes (for example, in a clustering setup to handle high traffic), similar performance constraints can emerge:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Resource Contention:&lt;/strong&gt; When every core is fully utilized by Node.js processes, offloading work to a worker thread can introduce additional context switching and inter-thread communication overhead. This may limit performance gains, especially for lightweight tasks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Marginal Gains for Lightweight Tasks:&lt;/strong&gt; For logging tasks that are designed to be lightweight and asynchronous, the extra overhead associated with worker threads might not translate into significant performance improvements compared to a well-optimized main-thread solution.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Worker Threads in Logging
&lt;/h3&gt;

&lt;p&gt;Logging is a critical aspect of many applications, and its implementation can significantly influence overall performance. There are two common approaches:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Main Thread Logging:&lt;/strong&gt; This traditional approach performs asynchronous I/O directly on the main thread. With proper optimization—such as using non-blocking I/O and connection pooling—this method can efficiently handle high volumes of log messages without causing significant delays.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Worker Thread Logging:&lt;/strong&gt; In this approach, logging operations are offloaded to a worker thread. This can be especially beneficial when the logging process involves heavy processing, such as complex formatting, data transformation, or buffering. Offloading these tasks helps to ensure that the main thread remains free to manage incoming requests.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  When Worker Threads May Not Offer Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;On Single-Core Systems:&lt;/strong&gt; Without true parallelism, the benefits of offloading work to a worker thread are reduced. The overhead from inter-thread communication and context switching can negate any potential advantages, particularly under heavy logging or CPU-intensive conditions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;On Multi-Core Systems with Full Node.js Utilization:&lt;/strong&gt; Even in multi-core environments, if all cores are already occupied by Node.js processes handling application traffic, the extra overhead introduced by worker threads might lead to performance bottlenecks for lightweight tasks. In such cases, a well-tuned main-thread logging approach could perform better.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Worker threads in Node.js provide a powerful mechanism for offloading CPU-intensive tasks and keeping the main event loop responsive. Their benefits are most pronounced in scenarios where heavy computational tasks can run concurrently on multi-core systems. However, on single-core machines—or even on multi-core systems where all cores are fully utilized by Node.js processes—the overhead associated with worker threads may outweigh their advantages, particularly for lightweight logging tasks.&lt;/p&gt;

&lt;p&gt;Ultimately, the decision to use worker threads for logging should be based on a careful analysis of your workload and the system’s resource utilization. Profiling your application under realistic conditions is essential to determine whether offloading to a worker thread offers tangible benefits over a well-optimized main-thread approach. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;To work best, a worker thread ideally should have a dedicated core so that under any condition, it can perform better without contending for resources with the main thread.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>node</category>
      <category>programming</category>
      <category>productivity</category>
      <category>learning</category>
    </item>
    <item>
      <title>Why Paid Logging Services Like BetterStack Can Hurt Your Throughput: Node.js</title>
      <dc:creator>Rishi Kumar</dc:creator>
      <pubDate>Fri, 21 Feb 2025 06:44:36 +0000</pubDate>
      <link>https://dev.to/mrrishimeena/why-paid-logging-services-like-betterstack-can-hurt-your-throughput-nodejs-34ci</link>
      <guid>https://dev.to/mrrishimeena/why-paid-logging-services-like-betterstack-can-hurt-your-throughput-nodejs-34ci</guid>
      <description>&lt;p&gt;I’ve been on a journey—one that started with a simple idea: &lt;strong&gt;&lt;em&gt;build a free open-source Node.js logger&lt;/em&gt;&lt;/strong&gt;. (&lt;em&gt;No, I’m not going to name it because this isn’t a promotional story—just an honest one.&lt;/em&gt;)&lt;/p&gt;

&lt;p&gt;I tested many logging tools—both open-source and paid. Each had its pluses and minuses, but let me share my experience with one paid service: Better Stack.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It's not just about Better Stack. It's about many paid logging services.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The results of Better Stack vs Open-source logging services:

Better Stack (HTTP endpoint): ~110k requests/min
Open-source (LocalDB): ~300k requests/min
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why this performance discrepancy happens and why a paid logging service that relies on HTTP/HTTPS can bring your system’s throughput down.&lt;/p&gt;




&lt;h2&gt;
  
  
  Paid Logging Services and Their Drawbacks
&lt;/h2&gt;

&lt;p&gt;Paid logging services often provide many other services with logging services. But if you into only logging service feature then this may help you to decide what to chose between paid service / open source logger.&lt;/p&gt;

&lt;p&gt;Take Better Stack’s logging feature, for instance. In a recent performance test, using &lt;code&gt;winston-betterstack&lt;/code&gt; to ship logs to Better Stack’s remote endpoint yielded only around &lt;strong&gt;110k requests/min&lt;/strong&gt; throughput. This performance is notably lower than many self‑hosted or local logging setups, which often reach upwards of &lt;strong&gt;300k requests/min&lt;/strong&gt;.&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%2Fx1ha4cgc50692p0ap6uh.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%2Fx1ha4cgc50692p0ap6uh.png" alt="winston-betterstack performance screenshot" width="800" height="317"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, &lt;strong&gt;why the discrepancy?&lt;/strong&gt;  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;HTTP/HTTPS Overhead&lt;/strong&gt;: Logging to a remote service requires creating outbound HTTP requests for every log entry. This is inherently slower than writing directly to a local or same‑network database, where you can use efficient protocols and avoid extra layers of latency.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Extra Network Hops&lt;/strong&gt;: Sending logs across the internet means more points of failure and potential congestion. You rely on your connection stability, the remote provider’s ingestion pipeline, and everything in between.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Rate Limiting &amp;amp; Throttling&lt;/strong&gt;: Paid logging services often enforce ingestion or rate limits to protect their shared infrastructure. During traffic spikes, you risk losing critical logs or facing significant ingestion delays. For example, if you push logs via &lt;code&gt;pino-betterstack&lt;/code&gt; at high volumes, you might suddenly hit throttling thresholds—and lose logs right when you need them the most.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Added Cost&lt;/strong&gt;: Beyond slower performance, you’re also locked into monthly fees or usage‑based billing. If your application scales, you may find that your logging bills become larger and less predictable.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In short, &lt;strong&gt;paid services that rely on remote endpoints inherently add latency and can limit throughput.&lt;/strong&gt; Plus, they’re multi-tenant, so you share resources and bandwidth with countless other users. All it takes is one usage surge—yours or another tenant’s—to stall or throttle your logs.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Benefits of Open-Source Logging Solutions
&lt;/h2&gt;

&lt;p&gt;If the drawbacks of paid services concern you, the good news is that &lt;strong&gt;open-source and self-hosted&lt;/strong&gt; alternatives can address most of these pain points. Whether you’re storing logs in MySQL, Postgres, or even using the ELK stack (Elasticsearch, Logstash, and Kibana), open-source systems put &lt;strong&gt;you&lt;/strong&gt; in control.&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%2Ftirzkuffxatavqxsgptz.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%2Ftirzkuffxatavqxsgptz.png" alt="errsole-postgres performance screenshot" width="800" height="283"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here’s why that’s a game-changer:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Faster and More Direct&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When you log to a locally hosted or network‑close database, you bypass the overhead of HTTP requests and external networks. In many cases, the data flows directly through a binary protocol (e.g., MySQL’s native protocol), significantly reducing latency. &lt;/li&gt;
&lt;li&gt;Typical throughput comparisons can show 300k+ requests/min on self‑hosted systems, which outperforms remote logging to Better Stack or similar paid providers.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Full Control Over the Pipeline&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;With open-source tools, you control your hardware, network settings, and data storage configurations. You can tune MySQL, for instance, to optimize write performance or replicate data across multiple nodes without third‑party constraints.
&lt;/li&gt;
&lt;li&gt;No arbitrary rate limits or forced throttling. You can choose to scale horizontally, add caching layers, or adjust ingestion queues according to your application’s needs.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cost‑Effectiveness&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open‑source solutions are free to use—your main costs are infrastructure and time. That can lead to significant savings once you pass a certain scale, especially if you’re using existing servers or shared resources.&lt;/li&gt;
&lt;li&gt;You won’t be blindsided by usage‑based pricing or sudden overage fees.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Avoid Vendor Lock-In&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Proprietary platforms make it harder to switch providers because your logs and integrations live behind their paywall. In contrast, open-source solutions store your data in standard formats you control. If you need to migrate or pivot, you can do so without being chained to a provider’s platform.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Community-Driven Development&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open-source projects benefit from a community of contributors who actively improve performance, fix bugs, and release new features. As a user, you can file issues, submit pull requests, or just benefit from the collective expertise of a global user base.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;In summary,&lt;/strong&gt; open-source logging solutions give you the freedom to manage your logs at scale without worrying about throttling, arbitrary limits, or hidden fees. While paid services might be convenient for smaller shops or teams that need quick deployment and can tolerate lower throughput, &lt;strong&gt;high‑performance applications will likely find more reliability, control, and cost‑savings in open-source, self‑hosted setups.&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Final Word
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Paid logging services&lt;/strong&gt; can provide a slick user experience—but if you value raw performance, cost control, and having complete ownership over your logs, they often fall short. As shown in our comparison with Better Stack, relying on an external HTTP endpoint can cap your throughput significantly and impose usage or rate limits that lead to dropped logs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Open-source solutions,&lt;/strong&gt; on the other hand, empower you with direct control over your infrastructure, letting you optimize for both speed and reliability. For teams that prioritize performance, scalability, and cost‑savings, self‑hosting is often the superior choice—and it avoids the headaches and constraints imposed by remote, multi-tenant providers.&lt;/p&gt;




&lt;p&gt;I know—setting up open-source or self-hosted solutions can be a hassle, while paid services are often simpler. Many open-source loggers require a complicated setup and some tech know-how. That’s why I built a Node.js logger that can be up and running in under a minute—so easy even an intern can do it!&lt;/p&gt;

&lt;p&gt;Also, there are lots of open-source logging tools out there. Some are old and solid, others are new with great speed and simple setup. There’s no absolute “best” or “worst” option—it really depends on what you need for your project.&lt;/p&gt;

</description>
      <category>node</category>
      <category>opensource</category>
      <category>performance</category>
      <category>programming</category>
    </item>
    <item>
      <title>The Magical World of Garbage Collection in Node.js</title>
      <dc:creator>Rishi Kumar</dc:creator>
      <pubDate>Wed, 19 Feb 2025 12:38:29 +0000</pubDate>
      <link>https://dev.to/mrrishimeena/the-magical-world-of-garbage-collection-in-nodejs-4pjo</link>
      <guid>https://dev.to/mrrishimeena/the-magical-world-of-garbage-collection-in-nodejs-4pjo</guid>
      <description>&lt;p&gt;&lt;em&gt;&lt;em&gt;How Your Code Stays Clean Without Lifting a Finger&lt;/em&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Imagine if your room could magically clean itself up every time you left a mess—no more piles of dirty dishes or clothes strewn everywhere. Well, in the world of Node.js, there’s something almost as awesome working behind the scenes: &lt;strong&gt;Garbage Collection (GC)&lt;/strong&gt;. And yes, it’s as cool as it sounds!&lt;/p&gt;

&lt;p&gt;Let’s dive into this topic with a fun twist. Here’s a down-to-earth, no-fluff guide that explains how Node.js’ GC works, why it’s your unsung hero, and a few tips that will actually help you improve your code’s performance. Let’s get started!&lt;/p&gt;




&lt;h2&gt;
  
  
  What’s Garbage Collection Anyway?
&lt;/h2&gt;

&lt;p&gt;Picture your Node.js application as a bustling kitchen. Every time you whip up a meal (i.e., create an object), you use ingredients (memory). Eventually, you finish cooking, but the ingredients and tools remain on the counter, cluttering your workspace. Garbage Collection is like that magical helper who comes in, tidies up, and throws away the leftovers you no longer need—so you have plenty of room to keep cooking without tripping over a mess.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Secret Life of GC in Node.js (Powered by V8)
&lt;/h2&gt;

&lt;p&gt;Node.js rides on the back of the V8 engine, which has its own nifty way of handling garbage collection. Let’s break it down in a fun, relatable way:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Young vs. Old Generation: The Teenage Rebels and Seasoned Veterans&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Young Generation (The Teenagers):&lt;/strong&gt;&lt;br&gt;
Think of these objects as rebellious teenagers—new, energetic, and likely to disappear quickly. V8 uses a &lt;strong&gt;copying algorithm&lt;/strong&gt; here. It quickly sweeps through, moving the survivors (the few that manage to stick around) to a more mature area.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Old Generation (The Veterans):&lt;/strong&gt;&lt;br&gt;
Now, the objects that survive the wild teenage phase become the "old generation"—loyal, stable, and around for the long haul. Cleaning up here is a bit more involved, often using a &lt;strong&gt;mark-sweep&lt;/strong&gt; or &lt;strong&gt;mark-compact&lt;/strong&gt; method, but hey, these veterans deserve a careful cleanup!&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. &lt;strong&gt;Incremental &amp;amp; Concurrent GC: Cleaning Without the Drama&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Imagine your magical cleaning helper working in small, almost invisible bursts instead of a massive all-day cleaning frenzy.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Incremental Marking:&lt;/strong&gt;
This breaks down the cleaning process into small chunks so your app doesn’t freeze up for a long time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Concurrent Sweeping:&lt;/strong&gt;
Parts of the cleanup happen while your app is still busy doing its thing. No long pauses—just smooth, nearly invisible maintenance.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  How to Peek Behind the Curtain: Detecting GC in Action
&lt;/h2&gt;

&lt;p&gt;Even though GC works its magic quietly, sometimes you need to know what’s going on under the hood—especially when your app seems to lag or memory usage starts creeping up. Here are some tricks to help you spot GC in action:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Turn on the GC Radar with Runtime Flags&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Fire up your Node.js app with these flags to see real-time GC events:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node &lt;span class="nt"&gt;--trace_gc&lt;/span&gt; your-app.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command prints GC events to your console. It’s like having a window into the cleaning crew’s schedule.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. Use Chrome DevTools for a Closer Look&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Start Node.js with the &lt;code&gt;--inspect&lt;/code&gt; flag, and open Chrome DevTools to inspect memory usage. The &lt;strong&gt;Memory&lt;/strong&gt; tab lets you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Take heap snapshots.&lt;/li&gt;
&lt;li&gt;Monitor object allocation.&lt;/li&gt;
&lt;li&gt;Identify memory leaks.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3. Bring in the Heavy Machinery: Profiling Tools&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;For more detailed insights, try tools like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;clinic.js:&lt;/strong&gt; Visualizes performance issues.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;heapdump:&lt;/strong&gt; Captures snapshots of your heap to find stubborn memory hogs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;node-memwatch:&lt;/strong&gt; Alerts you about leaks and GC events.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Real-World Scenarios: When GC Can Trip You Up
&lt;/h2&gt;

&lt;p&gt;Even with its magical prowess, GC can sometimes cause hiccups in your application. Here’s what to watch for and how to tackle it:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Memory Leaks: The Unwanted Houseguests&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Symptoms:&lt;/strong&gt; Gradually increasing memory usage, frequent long GC pauses, and, eventually, your app getting sluggish or crashing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pro Tip:&lt;/strong&gt; Regularly profile your app with heap snapshots. Keep an eye on closures, global variables, and event listeners that might be holding onto memory longer than needed.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;High GC Pauses: When the Cleaning Crew Overdoes It&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Symptoms:&lt;/strong&gt; Noticeable stutters or freezes during heavy object creation and deletion.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Workaround:&lt;/strong&gt; Optimize your code by reducing unnecessary object creation. Think about reusing objects or using object pools for things that get created and destroyed frequently.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;GC Overhead in High-Throughput Systems&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt; Your app is handling thousands of requests per second, and the GC is working overtime to clean up all those ephemeral objects.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Consider refactoring critical paths to minimize short-lived allocations. Use performance monitoring (APM tools like New Relic or Datadog) to spot and address these issues before they impact users.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Embrace the Magic!
&lt;/h2&gt;

&lt;p&gt;Garbage Collection in Node.js isn’t just a background process—it’s a sophisticated, finely-tuned system that keeps your app running smoothly without you having to sweat the small stuff. By understanding the basics of how GC works (and having some fun with it), you can write cleaner, more efficient code and avoid common pitfalls like memory leaks and performance lags.&lt;/p&gt;

&lt;p&gt;So next time you marvel at how your Node.js app manages to stay performant despite a chaotic codebase, give a nod to the unsung hero: Garbage Collection. It’s working hard behind the scenes, so you can focus on building awesome features without getting bogged down in manual memory management.&lt;/p&gt;

&lt;p&gt;Below is your original "Magical World of Garbage Collection" article with additional details appended. The original text remains unchanged, and the extra sections provide more insights for those who crave a bit more technical magic!&lt;/p&gt;




&lt;h2&gt;
  
  
  Bonus: Extra Magical Tidbits for the Adventurous Developer
&lt;/h2&gt;

&lt;p&gt;While we’ve journeyed through the enchanting basics of GC, here are some extra details and tools to help you master the art of memory management in Node.js:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Dive Deeper into the V8 Engine&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Major vs. Minor GC:&lt;/strong&gt; Remember, the young generation’s minor GCs are quick sprinkles of magic, while the old generation’s major GCs are like a deep cleaning session. These full GCs scan the entire heap and are more performance-intensive—so watch out when your app starts to slow down.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tuning Your Memory:&lt;/strong&gt; Experiment with Node.js runtime flags like &lt;code&gt;--max-old-space-size&lt;/code&gt; to control how much memory your app can use. Adjusting these settings can help manage GC behavior during heavy loads.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Unleash the Power of Profiling Tools&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Chrome DevTools &amp;amp; Heap Snapshots:&lt;/strong&gt; Launch your app with the &lt;code&gt;--inspect&lt;/code&gt; flag and connect via Chrome DevTools. The Memory tab isn’t just for pretty pictures—it lets you take snapshots of your heap, track object lifetimes, and pinpoint those sneaky memory leaks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Advanced Tools:&lt;/strong&gt; Give tools like &lt;a href="https://clinicjs.org/" rel="noopener noreferrer"&gt;Clinic.js&lt;/a&gt; a whirl to visualize performance bottlenecks, or use &lt;a href="https://www.npmjs.com/package/heapdump" rel="noopener noreferrer"&gt;heapdump&lt;/a&gt; to capture the state of your memory during runtime. These tools add an extra layer of magic to your debugging process.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Modern Spells: WeakRef and FinalizationRegistry&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Harnessing New ECMAScript Features:&lt;/strong&gt; With WeakRef and FinalizationRegistry, you can create weak references to objects. This means your objects can vanish when they’re no longer needed, without holding up the GC process. It’s like setting up a farewell party for your objects!&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Watch Out for Memory Gremlins&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Memory Leaks &amp;amp; Lingering Closures:&lt;/strong&gt; Sometimes, those pesky global variables, event listeners, or closures can hold onto memory longer than they should. Keep your code tidy by reviewing these potential trouble spots and running regular memory profilers.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Experiment, Benchmark, and Learn&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Iterative Magic:&lt;/strong&gt; The realm of garbage collection is ever-evolving. Try different coding patterns, benchmark your changes, and learn from each magical tweak you make. With practice, you’ll find the perfect balance for your Node.js applications.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>node</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Stream and HighWatermark: Node.js</title>
      <dc:creator>Rishi Kumar</dc:creator>
      <pubDate>Fri, 31 Jan 2025 06:54:59 +0000</pubDate>
      <link>https://dev.to/mrrishimeena/stream-and-highwatermark-nodejs-44kd</link>
      <guid>https://dev.to/mrrishimeena/stream-and-highwatermark-nodejs-44kd</guid>
      <description>&lt;p&gt;Understanding the interplay between &lt;code&gt;objectMode&lt;/code&gt; and &lt;code&gt;highWaterMark&lt;/code&gt; is essential for optimizing stream performance in Node.js. Let's delve into what each term means, how they interact, and whether &lt;code&gt;objectMode&lt;/code&gt; improves &lt;code&gt;highWaterMark&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Understanding &lt;code&gt;highWaterMark&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Understanding &lt;code&gt;objectMode&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Interaction Between &lt;code&gt;objectMode&lt;/code&gt; and &lt;code&gt;highWaterMark&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Does &lt;code&gt;objectMode&lt;/code&gt; Improve &lt;code&gt;highWaterMark&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;Best Practices&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Understanding &lt;code&gt;highWaterMark&lt;/code&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is &lt;code&gt;highWaterMark&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;highWaterMark&lt;/code&gt; is a configuration option in Node.js streams that specifies the threshold at which the stream will apply backpressure. It essentially determines how much data can be buffered in the stream before it starts to signal that it's "full" and needs to pause or slow down the incoming data.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Readable Streams&lt;/strong&gt;: For readable streams, &lt;code&gt;highWaterMark&lt;/code&gt; defines the maximum number of bytes (in binary mode) or objects (in object mode) to store in the internal buffer before ceasing to read from the underlying resource.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Writable Streams&lt;/strong&gt;: For writable streams, it indicates the maximum number of bytes or objects that can be buffered while writing data before applying backpressure to the source.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Default Values
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Binary Mode&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Readable Streams&lt;/strong&gt;: 16 KB (&lt;code&gt;16 * 1024&lt;/code&gt; bytes)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Writable Streams&lt;/strong&gt;: 16 KB (&lt;code&gt;16 * 1024&lt;/code&gt; bytes)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Object Mode&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Both readable and writable streams default to a &lt;code&gt;highWaterMark&lt;/code&gt; of &lt;code&gt;16&lt;/code&gt; objects.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;The above defaults are stable in modern Node.js versions (e.g., Node 14+). If you’re on an older version of Node, be sure to check the docs to confirm these defaults.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Why is &lt;code&gt;highWaterMark&lt;/code&gt; Important?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Memory Management&lt;/strong&gt;: Prevents excessive memory usage by limiting the amount of data buffered.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flow Control&lt;/strong&gt;: Ensures smooth data flow between producers and consumers without overwhelming either side.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance Optimization&lt;/strong&gt;: Balances throughput and latency based on the application's requirements.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Understanding &lt;code&gt;objectMode&lt;/code&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is &lt;code&gt;objectMode&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;objectMode&lt;/code&gt; is a stream option in Node.js that allows streams to handle arbitrary JavaScript objects instead of raw binary data (&lt;code&gt;Buffer&lt;/code&gt;) or strings. When &lt;code&gt;objectMode&lt;/code&gt; is enabled, the stream operates in "object mode," treating each chunk as a distinct object.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enabling &lt;code&gt;objectMode&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;To enable &lt;code&gt;objectMode&lt;/code&gt;, set the &lt;code&gt;objectMode&lt;/code&gt; option to &lt;code&gt;true&lt;/code&gt; when creating a stream:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Readable&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;stream&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;objectReadable&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;Readable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;objectMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nf"&gt;read&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;h3&gt;
  
  
  Benefits of &lt;code&gt;objectMode&lt;/code&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Structured Data Handling&lt;/strong&gt;: Ideal for streaming complex data structures like JSON objects, database records, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simplified Processing&lt;/strong&gt;: Easier to work with objects directly without manual serialization/deserialization.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexibility&lt;/strong&gt;: Can handle varying data types and structures seamlessly.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Keep in mind that objectMode can add a little overhead compared to binary mode, because the stream must handle discrete JavaScript objects rather than raw bytes. In most real-world use cases (like streaming database records), this overhead is negligible compared to the clarity gained when working with structured data.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Interaction Between &lt;code&gt;objectMode&lt;/code&gt; and &lt;code&gt;highWaterMark&lt;/code&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How They Work Together
&lt;/h3&gt;

&lt;p&gt;When &lt;code&gt;objectMode&lt;/code&gt; is enabled, the interpretation of &lt;code&gt;highWaterMark&lt;/code&gt; changes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Binary Mode&lt;/strong&gt;: &lt;code&gt;highWaterMark&lt;/code&gt; is measured in bytes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Object Mode&lt;/strong&gt;: &lt;code&gt;highWaterMark&lt;/code&gt; is measured in the number of objects.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, a &lt;code&gt;highWaterMark&lt;/code&gt; of &lt;code&gt;16&lt;/code&gt; in object mode means the internal buffer can hold up to 16 objects, regardless of their size.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implications
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Granularity&lt;/strong&gt;: Object mode provides a more granular control based on the number of discrete objects rather than their byte size.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistency&lt;/strong&gt;: Each object is treated equally, making buffer management predictable regardless of individual object sizes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backpressure Signaling&lt;/strong&gt;: The stream can more accurately signal backpressure based on object count, which is particularly useful when object sizes vary significantly.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Does &lt;code&gt;objectMode&lt;/code&gt; Improve &lt;code&gt;highWaterMark&lt;/code&gt;?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Clarifying "Improve"
&lt;/h3&gt;

&lt;p&gt;The term "improve" can be subjective, but in this context, it likely refers to whether using &lt;code&gt;objectMode&lt;/code&gt; enhances the effectiveness or efficiency of &lt;code&gt;highWaterMark&lt;/code&gt; in managing stream buffers and backpressure.&lt;/p&gt;

&lt;h3&gt;
  
  
  How &lt;code&gt;objectMode&lt;/code&gt; Affects &lt;code&gt;highWaterMark&lt;/code&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Consistency in Buffer Management&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Object Mode&lt;/strong&gt;: Each object, regardless of size, is counted uniformly. This consistency is beneficial when dealing with objects of varying sizes, ensuring that buffer limits are based on the number of discrete items rather than their potentially unpredictable byte sizes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Binary Mode&lt;/strong&gt;: Buffer limits are based on byte sizes, which can be problematic if object sizes vary widely, leading to inefficient memory usage or unexpected backpressure triggers.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Predictable Backpressure&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Object Mode&lt;/strong&gt;: By limiting the number of objects, developers can predict and manage backpressure more accurately, especially when object sizes are inconsistent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Binary Mode&lt;/strong&gt;: Backpressure is tied to byte counts, which may not directly correlate with processing capabilities, especially when dealing with large or small objects.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ease of Configuration&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Object Mode&lt;/strong&gt;: Setting &lt;code&gt;highWaterMark&lt;/code&gt; based on the number of objects is often more intuitive when dealing with streams of objects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Binary Mode&lt;/strong&gt;: Requires careful consideration of byte sizes, which may vary and complicate buffer management.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Does It "Improve" &lt;code&gt;highWaterMark&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;In scenarios where streams handle discrete, structured objects with varying sizes, &lt;code&gt;objectMode&lt;/code&gt; &lt;strong&gt;enhances&lt;/strong&gt; the effectiveness of &lt;code&gt;highWaterMark&lt;/code&gt; by providing a more logical and consistent buffer management strategy. It allows developers to control the flow based on the number of objects, leading to more predictable backpressure behavior.&lt;/p&gt;

&lt;p&gt;However, it's essential to note that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Use Case Dependent&lt;/strong&gt;: The benefits are most pronounced when dealing with object streams. For binary or text streams, &lt;code&gt;objectMode&lt;/code&gt; is not applicable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance Considerations&lt;/strong&gt;: While &lt;code&gt;objectMode&lt;/code&gt; offers better control for object streams, it may introduce some overhead compared to binary streams due to object handling. However, this is generally negligible compared to the benefits in appropriate use cases.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Yes&lt;/strong&gt;, &lt;code&gt;objectMode&lt;/code&gt; can &lt;strong&gt;improve&lt;/strong&gt; the effectiveness of &lt;code&gt;highWaterMark&lt;/code&gt; when dealing with streams of JavaScript objects by providing a more intuitive and consistent way to manage buffer limits and backpressure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No&lt;/strong&gt;, in the sense that &lt;code&gt;objectMode&lt;/code&gt; doesn't inherently make &lt;code&gt;highWaterMark&lt;/code&gt; "better" for all types of streams; its benefits are context-specific.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Best Practices
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Choose the Right Mode&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;objectMode&lt;/code&gt; when streaming JavaScript objects.&lt;/li&gt;
&lt;li&gt;Use binary or text modes for streaming raw data like files, network packets, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set Appropriate &lt;code&gt;highWaterMark&lt;/code&gt; Values&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Object Mode&lt;/strong&gt;: Set based on the number of objects that can be comfortably buffered without exhausting memory or causing delays.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Binary Mode&lt;/strong&gt;: Set based on byte sizes that align with processing capabilities and memory constraints.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitor and Adjust&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Use tools and logging to monitor stream performance and adjust &lt;code&gt;highWaterMark&lt;/code&gt; as needed.&lt;/li&gt;
&lt;li&gt;Be mindful of the nature of your data; for instance, if objects are large, a lower &lt;code&gt;highWaterMark&lt;/code&gt; may be appropriate.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Handle Backpressure Properly&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Respect the &lt;code&gt;write()&lt;/code&gt; method's return value.&lt;/li&gt;
&lt;li&gt;Listen for the &lt;code&gt;drain&lt;/code&gt; event to resume data flow when appropriate.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;In Node.js, when a writable stream's internal buffer exceeds highWaterMark, the write() method will return false. That signals backpressure. You should then stop writing until the stream emits the drain event, which tells you it’s ready for more data. For readable streams, the flow can be paused automatically or manually (via pause() and resume()).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Optimize Stream Pipelines&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;stream.pipeline&lt;/code&gt; for better error handling and cleaner stream composition.&lt;/li&gt;
&lt;li&gt;Ensure all streams in the pipeline are correctly configured for &lt;code&gt;objectMode&lt;/code&gt; if needed.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Avoid Unnecessary Object Mode&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Enabling &lt;code&gt;objectMode&lt;/code&gt; when not needed can lead to increased memory usage and processing overhead.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Practical Example
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Object Mode vs. Binary Mode with &lt;code&gt;highWaterMark&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Let's illustrate how &lt;code&gt;objectMode&lt;/code&gt; affects &lt;code&gt;highWaterMark&lt;/code&gt; with a practical example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Readable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Writable&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;stream&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Binary Mode Example&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;binaryReadable&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;Readable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;highWaterMark&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 1 KB&lt;/span&gt;
  &lt;span class="nf"&gt;read&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;binaryWritable&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;Writable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;highWaterMark&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 2 KB&lt;/span&gt;
  &lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;encoding&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&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="s2"&gt;`Writing &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;chunk&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="s2"&gt; bytes`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;callback&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="nx"&gt;binaryReadable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;binaryWritable&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Push data&lt;/span&gt;
&lt;span class="nx"&gt;binaryReadable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;alloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// Within highWaterMark&lt;/span&gt;
&lt;span class="nx"&gt;binaryReadable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;alloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// Exceeds highWaterMark, triggers backpressure&lt;/span&gt;
&lt;span class="nx"&gt;binaryReadable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// End the stream&lt;/span&gt;

&lt;span class="c1"&gt;// Object Mode Example&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;objectReadable&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;Readable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;objectMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;highWaterMark&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 2 objects&lt;/span&gt;
  &lt;span class="nf"&gt;read&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;objectWritable&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;Writable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;objectMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;highWaterMark&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 3 objects&lt;/span&gt;
  &lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;encoding&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&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="s2"&gt;`Writing object:`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;callback&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="nx"&gt;objectReadable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;objectWritable&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Push objects&lt;/span&gt;
&lt;span class="nx"&gt;objectReadable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&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="s1"&gt;Alice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// Within highWaterMark&lt;/span&gt;
&lt;span class="nx"&gt;objectReadable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&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="s1"&gt;Bob&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;   &lt;span class="c1"&gt;// Within highWaterMark&lt;/span&gt;
&lt;span class="nx"&gt;objectReadable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&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="s1"&gt;Charlie&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// Exceeds highWaterMark, triggers backpressure&lt;/span&gt;
&lt;span class="nx"&gt;objectReadable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// End the stream&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Explanation&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Binary Mode&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;binaryReadable&lt;/code&gt; stream has a &lt;code&gt;highWaterMark&lt;/code&gt; of 1 KB.&lt;/li&gt;
&lt;li&gt;Pushing 500 bytes is fine, but pushing an additional 600 bytes exceeds the &lt;code&gt;highWaterMark&lt;/code&gt;, triggering backpressure.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Object Mode&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;objectReadable&lt;/code&gt; stream has a &lt;code&gt;highWaterMark&lt;/code&gt; of 2 objects.&lt;/li&gt;
&lt;li&gt;Pushing three objects exceeds the &lt;code&gt;highWaterMark&lt;/code&gt;, triggering backpressure based on the number of objects, not their size.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

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

&lt;p&gt;&lt;code&gt;objectMode&lt;/code&gt; and &lt;code&gt;highWaterMark&lt;/code&gt; are powerful configurations in Node.js streams that, when used together appropriately, can significantly enhance stream performance and reliability:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;objectMode&lt;/code&gt;&lt;/strong&gt; allows streams to handle JavaScript objects seamlessly, providing a natural way to work with structured data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;highWaterMark&lt;/code&gt;&lt;/strong&gt; controls the buffering strategy, ensuring that streams do not overwhelm system resources by limiting the amount of data buffered.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By enabling &lt;code&gt;objectMode&lt;/code&gt; when dealing with object streams, you can &lt;strong&gt;improve the effectiveness&lt;/strong&gt; of &lt;code&gt;highWaterMark&lt;/code&gt; by aligning buffer management with the nature of your data. This leads to more predictable backpressure behavior, efficient memory usage, and smoother data flow within your applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  Final Tips
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Assess Your Data&lt;/strong&gt;: Determine whether your stream handles objects or binary data to choose the appropriate mode.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configure Thoughtfully&lt;/strong&gt;: Set &lt;code&gt;highWaterMark&lt;/code&gt; based on the specific needs and constraints of your application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test and Iterate&lt;/strong&gt;: Monitor stream behavior under different loads and adjust configurations to achieve optimal performance.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have more specific scenarios or further questions about &lt;code&gt;objectMode&lt;/code&gt; and &lt;code&gt;highWaterMark&lt;/code&gt;, feel free to comment!&lt;/p&gt;

</description>
      <category>node</category>
      <category>programming</category>
      <category>productivity</category>
      <category>learning</category>
    </item>
    <item>
      <title>Log Viewer for Next.js Server Side: Node.js</title>
      <dc:creator>Rishi Kumar</dc:creator>
      <pubDate>Wed, 22 Jan 2025 10:01:22 +0000</pubDate>
      <link>https://dev.to/mrrishimeena/log-viewer-for-nextjs-server-side-nodejs-5a56</link>
      <guid>https://dev.to/mrrishimeena/log-viewer-for-nextjs-server-side-nodejs-5a56</guid>
      <description>&lt;p&gt;Logging on the server side is vital when you’re building applications with Next.js. Server-side rendering (SSR) introduces unique challenges and potential errors that client-side logs can’t capture.&lt;/p&gt;

&lt;p&gt;Let's walk through how to integrate &lt;a href="https://github.com/errsole/errsole.js" rel="noopener noreferrer"&gt;Errsole&lt;/a&gt; into your Next.js application for a clean, insightful logging experience. You’ll see how to start logging quickly using SQLite for local storage and also learn about options for more centralized solutions such as MySQL or PostgreSQL.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Why Server-Side Logging Is Important
&lt;/h2&gt;

&lt;p&gt;When Next.js renders pages on the server, it’s crucial to have a clear view of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Application Health&lt;/strong&gt;: Identify performance bottlenecks or errors impacting server-side rendering. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debugging&lt;/strong&gt;: Pin down issues that never surface on the client side. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security and Auditing&lt;/strong&gt;: Track suspicious or unexpected behaviors in your server logs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A well-organized logging system makes these tasks straightforward, and Errsole provides a user-friendly way to capture and view these logs.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Install Errsole and Errsole-SQLite
&lt;/h2&gt;

&lt;p&gt;Let’s start by installing Errsole and its SQLite storage plugin. SQLite offers a simple, file-based database—perfect for local development or small-scale projects.&lt;br&gt;
&lt;/p&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;errsole errsole-sqlite
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip&lt;/strong&gt;: If you need a more centralized solution in production, Errsole also supports:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;errsole-mysql&lt;/strong&gt; for MySQL
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;errsole-postgres&lt;/strong&gt; for PostgreSQL
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;errsole-mongodb&lt;/strong&gt; for MongoDB&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  3. Create a Logger File (&lt;code&gt;logger.js&lt;/code&gt;)
&lt;/h2&gt;

&lt;p&gt;To keep your logging setup organized, we’ll create a dedicated file for initializing Errsole. Place this file in a &lt;code&gt;lib&lt;/code&gt; folder. By doing this, you can import your logger into all your server-side routes under &lt;code&gt;pages/api&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// lib/logger.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;errsole&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;errsole&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="nx"&gt;ErrsoleSQLite&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;errsole-sqlite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Initialize Errsole&lt;/span&gt;
&lt;span class="nx"&gt;errsole&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;storage&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;ErrsoleSQLite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path/to/database.sqlite&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="c1"&gt;// Export errsole to use throughout your app&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;errsole&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s what’s happening:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Importing Errsole&lt;/strong&gt;: We bring in the core &lt;code&gt;errsole&lt;/code&gt; module and the &lt;code&gt;errsole-sqlite&lt;/code&gt; plugin. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Initialize&lt;/strong&gt;: We configure Errsole to store logs in an SQLite database. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Export&lt;/strong&gt;: We export our initialized logger so it can be reused across your project.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  4. Use the Logger in API Routes
&lt;/h2&gt;

&lt;p&gt;Now that we have our logger set up, let’s see how to log events in a Next.js API route. Any file in the &lt;code&gt;pages/api&lt;/code&gt; directory runs on the server side, making it the perfect place for server logs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// pages/api/hello.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;logger&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;../../lib/logger&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Log an info message&lt;/span&gt;
  &lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;API /hello was called&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Simulate an error scenario&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;errorHappened&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&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;errorHappened&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Something went wrong in /hello!&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&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="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello from Next.js + Errsole!&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;h3&gt;
  
  
  Logging Levels
&lt;/h3&gt;

&lt;p&gt;Errsole supports various log levels (&lt;code&gt;info&lt;/code&gt;, &lt;code&gt;error&lt;/code&gt;, &lt;code&gt;warn&lt;/code&gt;, etc.), so you can categorize logs by severity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;info&lt;/strong&gt;: General operational messages. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;warn&lt;/strong&gt;: Something unexpected but not breaking. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;error&lt;/strong&gt;: An error that needs immediate attention.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using these levels consistently makes filtering and searching through logs much easier down the line.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Viewing Logs in the Errsole Dashboard
&lt;/h2&gt;

&lt;p&gt;One of Errsole’s standout features is its &lt;strong&gt;Web Dashboard&lt;/strong&gt;, which displays real-time logs and error insights in a central location. &lt;/p&gt;

&lt;p&gt;After completing the setup, you can access the Errsole Web Dashboard through the following methods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Local Environment&lt;/strong&gt;: Open your web browser and visit &lt;a href="http://localhost:8001/" rel="noopener noreferrer"&gt;http://localhost:8001/&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Remote Server&lt;/strong&gt;: If you have deployed Errsole on a remote server, use the server's IP address or domain name followed by the port number (e.g., YourServerIP:8001 or YourDomain:8001).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once done, you’ll see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Timeline and Filtering&lt;/strong&gt;: Search logs by date, severity, or message content. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error Stacks&lt;/strong&gt;: Detailed error context, including stack traces. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-time Updates&lt;/strong&gt;: Watch logs appear as they happen.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Collaboration&lt;/strong&gt;: Invite your teammates to join and work together to monitor logs effectively.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Advanced Tip&lt;/strong&gt;: For multi-app setups, you can assign different table prefixes or database files for each project to keep logs separate.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  6. Centralized Logging (MySQL, PostgreSQL, etc.)
&lt;/h2&gt;

&lt;p&gt;If your application is at scale or you need advanced reporting capabilities, consider integrating a more robust database.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example: Using MySQL
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// lib/logger.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;errsole&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;errsole&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="nx"&gt;ErrsoleMySQL&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;errsole-mysql&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;errsole&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;storage&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;ErrsoleMySQL&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mysql-host&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;database-user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;database-password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;database-name&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="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;errsole&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Similarly, you can use &lt;strong&gt;errsole-postgres&lt;/strong&gt;, &lt;strong&gt;errsole-mongodb&lt;/strong&gt;, or other supported databases for comprehensive log management.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Configure NGINX
&lt;/h2&gt;

&lt;p&gt;If your app is behind an NGINX reverse proxy, you can configure access to the Errsole Web Dashboard by adding the following lines to your NGINX configuration file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;location = /helloworld/logs {
  return 301 /helloworld/logs/;
}
location /helloworld/logs/ {
  proxy_pass http://localhost:8001/;
  proxy_http_version 1.1;
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection "upgrade";
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After updating the configuration, reload NGINX:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo nginx -s reload
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now access the dashboard through your domain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For HTTP: &lt;a href="http://YourDomain/helloworld/logs/" rel="noopener noreferrer"&gt;http://YourDomain/helloworld/logs/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;For HTTPS: &lt;a href="https://YourDomain/helloworld/logs/" rel="noopener noreferrer"&gt;https://YourDomain/helloworld/logs/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Replace &lt;code&gt;/helloworld/logs&lt;/code&gt; with your desired log path.&lt;/p&gt;




&lt;h2&gt;
  
  
  8. Advanced Configuration
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Option&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Type&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;storage&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://github.com/errsole/errsole.js/blob/master/docs/sqlite-storage.md" rel="noopener noreferrer"&gt;ErrsoleSQLite&lt;/a&gt;&lt;br&gt;&lt;a href="https://github.com/errsole/errsole.js/blob/master/docs/mongodb-storage.md" rel="noopener noreferrer"&gt;ErrsoleMongoDB&lt;/a&gt;&lt;br&gt;&lt;a href="https://github.com/errsole/errsole.js/blob/master/docs/mysql-storage.md" rel="noopener noreferrer"&gt;ErrsoleMySQL&lt;/a&gt;&lt;br&gt;&lt;a href="https://github.com/errsole/errsole.js/blob/master/docs/postgresql-storage.md" rel="noopener noreferrer"&gt;ErrsolePostgres&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Required.&lt;/strong&gt; Specify the storage backend along with connection details.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;collectLogs&lt;/td&gt;
&lt;td&gt;Array of Strings&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Optional.&lt;/strong&gt; Default: &lt;code&gt;['error', 'info']&lt;/code&gt;. By default, Errsole collects both error and info logs. To collect only error logs, set this to &lt;code&gt;['error']&lt;/code&gt;. To disable log collection entirely, set this to an empty array, &lt;code&gt;[]&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;enableConsoleOutput&lt;/td&gt;
&lt;td&gt;Boolean&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Optional.&lt;/strong&gt; Control whether log output is shown in the console.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;exitOnException&lt;/td&gt;
&lt;td&gt;Boolean&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Optional.&lt;/strong&gt; Default: &lt;code&gt;true&lt;/code&gt;. By default, Errsole exits the process after capturing an uncaught exception. To disable this behavior, set exitOnException to &lt;code&gt;false&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;enableDashboard&lt;/td&gt;
&lt;td&gt;Boolean&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Optional.&lt;/strong&gt; Default: &lt;code&gt;true&lt;/code&gt;. Enable or disable the web dashboard feature.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;port&lt;/td&gt;
&lt;td&gt;Number&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Optional.&lt;/strong&gt; Default: &lt;code&gt;8001&lt;/code&gt;. Specify the network port for the web dashboard.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;path&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Optional.&lt;/strong&gt; Default: &lt;code&gt;/&lt;/code&gt;. Define the base path for accessing the web dashboard.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;appName&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Optional.&lt;/strong&gt; Specify the name of the app.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;environmentName&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Optional.&lt;/strong&gt; Default: &lt;code&gt;process.env.NODE_ENV&lt;/code&gt;. Specify the deployment environment.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;serverName&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Optional.&lt;/strong&gt; Default: the hostname of the machine. Specify the name of the server.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  9. Best Practices for Logging
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Use Descriptive Messages&lt;/strong&gt;: Make sure your log messages provide clear context—this helps when revisiting them in the future. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Avoid Over-Logging&lt;/strong&gt;: Log only what’s necessary. Too many logs can obscure important information and increase storage costs. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rotate or Archive&lt;/strong&gt;: In production, make sure to rotate logs periodically to keep your storage in check.&lt;/li&gt;
&lt;/ol&gt;




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

&lt;p&gt;By integrating &lt;strong&gt;Errsole&lt;/strong&gt; into your Next.js server, you’ll gain real-time visibility into your application’s health and performance. Whether you choose SQLite for local development or a more advanced database like MySQL or PostgreSQL for production, Errsole offers a user-friendly solution to capture, store, and review all your server-side logs in one place.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Takeaways&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Initialize Errsole in a dedicated &lt;code&gt;logger.js&lt;/code&gt; file under &lt;code&gt;lib/&lt;/code&gt; to keep things organized. &lt;/li&gt;
&lt;li&gt;Import this logger throughout your server routes for consistent, structured logging. &lt;/li&gt;
&lt;li&gt;Leverage the Errsole dashboard to view logs, filter them, and troubleshoot issues quickly. &lt;/li&gt;
&lt;li&gt;Scale to centralized logging options (MySQL, PostgreSQL, etc.) as your application grows.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this setup, you can confidently develop and maintain a robust Next.js application, keeping a close eye on everything happening behind the scenes! Enjoy the enhanced clarity and peace of mind that come with a proper logging strategy.&lt;/p&gt;




&lt;p&gt;A Next.js application with server-side logging using Errsole and MySQL. Clone or download the repository to experience it in action.&lt;/p&gt;

&lt;p&gt;GitHub Code: &lt;a href="https://github.com/DevSpeaks/nextjs-server-log-viewer" rel="noopener noreferrer"&gt;nextjs-server-log-viewer&lt;/a&gt; &lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>node</category>
      <category>opensource</category>
      <category>api</category>
    </item>
    <item>
      <title>Common Errors in Node.js and How to Fix Them</title>
      <dc:creator>Rishi Kumar</dc:creator>
      <pubDate>Thu, 09 Jan 2025 09:12:39 +0000</pubDate>
      <link>https://dev.to/mrrishimeena/common-errors-in-nodejs-and-how-to-fix-them-2om5</link>
      <guid>https://dev.to/mrrishimeena/common-errors-in-nodejs-and-how-to-fix-them-2om5</guid>
      <description>&lt;h1&gt;
  
  
  Common Errors in Node.js and How to Fix Them
&lt;/h1&gt;

&lt;p&gt;Node.js, celebrated for its highly scalable runtime environment, provides developers with a robust framework to build efficient, high-performance server-side applications. Nevertheless, its non-blocking, event-driven architecture introduces unique challenges that require a sophisticated understanding and systematic resolution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Syntax Errors&lt;/li&gt;
&lt;li&gt;Reference Errors&lt;/li&gt;
&lt;li&gt;Type Errors&lt;/li&gt;
&lt;li&gt;Module Not Found Errors&lt;/li&gt;
&lt;li&gt;EventEmitter Memory Leaks&lt;/li&gt;
&lt;li&gt;Unhandled Promise Rejections&lt;/li&gt;
&lt;li&gt;Asynchronous Programming Issues&lt;/li&gt;
&lt;li&gt;Error: Cannot Find Module&lt;/li&gt;
&lt;li&gt;Networking Errors&lt;/li&gt;
&lt;li&gt;Performance Issues&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Syntax Errors
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Definition
&lt;/h3&gt;

&lt;p&gt;Syntax errors arise from deviations in the structural rules of JavaScript, such as unbalanced braces, incorrect punctuation, or misuse of keywords. These errors prevent the interpreter from executing the code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;helloWorld&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="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello, World!&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;p&gt;This code snippet demonstrates a mismatch between the parentheses and curly braces.&lt;/p&gt;

&lt;h3&gt;
  
  
  Resolution
&lt;/h3&gt;

&lt;p&gt;✅ Debugging syntax errors involves reviewing the error messages provided by the interpreter, pinpointing the location of the issue, and resolving it. The corrected code is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;helloWorld&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello, World!&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;
  
  
  Reference Errors
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Definition
&lt;/h3&gt;

&lt;p&gt;Reference errors occur when an undeclared or out-of-scope variable is accessed. These errors commonly arise from programming oversights or scope mismanagement.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&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;myVar&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this instance, &lt;code&gt;myVar&lt;/code&gt; is referenced without prior declaration, leading to an error.&lt;/p&gt;

&lt;h3&gt;
  
  
  Resolution
&lt;/h3&gt;

&lt;p&gt;✅Ensure that variables are appropriately declared within their intended scope before use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;myVar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello&lt;/span&gt;&lt;span class="dl"&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;myVar&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Type Errors
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Definition
&lt;/h3&gt;

&lt;p&gt;Type errors occur when an operation is performed on a data type that does not support it. These errors often reveal logical flaws in the program.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Numbers do not have a &lt;code&gt;toUpperCase&lt;/code&gt; method, resulting in a type error.&lt;/p&gt;

&lt;h3&gt;
  
  
  Resolution
&lt;/h3&gt;

&lt;p&gt;✅ Align operations with compatible data types:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello&lt;/span&gt;&lt;span class="dl"&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;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Module Not Found Errors
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Definition
&lt;/h3&gt;

&lt;p&gt;Module Not Found errors occur when Node.js fails to locate a module specified in a &lt;code&gt;require&lt;/code&gt; or &lt;code&gt;import&lt;/code&gt; statement. This issue often stems from incorrect paths or missing dependencies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;express&lt;/code&gt; is not installed, the interpreter will throw an error.&lt;/p&gt;

&lt;h3&gt;
  
  
  Resolution
&lt;/h3&gt;

&lt;p&gt;✅ Use the Node.js package manager to install the missing module:&lt;br&gt;
&lt;/p&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;express
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Additionally, verify the module path and its existence within the project.&lt;/p&gt;




&lt;h2&gt;
  
  
  EventEmitter Memory Leaks
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Definition
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;EventEmitter&lt;/code&gt; class in Node.js facilitates event-driven programming by allowing objects to emit events and handle listeners. Memory leaks occur when excessive listeners are attached to an EventEmitter instance without proper management, leading to resource exhaustion.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem
&lt;/h3&gt;

&lt;p&gt;Each time a listener is registered using &lt;code&gt;.on()&lt;/code&gt; or &lt;code&gt;.addListener()&lt;/code&gt;, a reference is retained, which can accumulate indefinitely. Node.js issues a warning if the number of listeners exceeds the default threshold of 10:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(MaxListenersExceededWarning: Possible EventEmitter memory leak detected.)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;EventEmitter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;events&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;emitter&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;EventEmitter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&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="nx"&gt;emitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data&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="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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data event&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;h3&gt;
  
  
  Resolution
&lt;/h3&gt;

&lt;p&gt;✅ Increase the listener limit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;emitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setMaxListeners&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ Remove listeners when they are no longer needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;emitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;off&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;listener&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ For one-time listeners, use &lt;code&gt;.once()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;emitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;once&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data&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="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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data event&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Unhandled Promise Rejections
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Definition
&lt;/h3&gt;

&lt;p&gt;An unhandled promise rejection occurs when a promise is rejected without a corresponding &lt;code&gt;.catch()&lt;/code&gt; handler. This omission can destabilize applications, particularly in production environments.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Resolution
&lt;/h3&gt;

&lt;p&gt;✅ Attach &lt;code&gt;.catch()&lt;/code&gt; handlers to all promises:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ Employ &lt;code&gt;try...catch&lt;/code&gt; blocks with &lt;code&gt;async/await&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&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;data&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;someAsyncOperation&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;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&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;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error fetching data:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&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;✅ Set up a global error handler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unhandledRejection&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;reason&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;promise&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Unhandled Rejection:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Reason:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reason&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;
  
  
  Networking Errors
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Definition
&lt;/h3&gt;

&lt;p&gt;Networking errors arise from failed interactions between the application and external services. These issues include connection timeouts, DNS errors, and malformed HTTP requests.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;http&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://invalid-url&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;res&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;h3&gt;
  
  
  Resolution
&lt;/h3&gt;

&lt;p&gt;✅ Incorporate error handling:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;http&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://invalid-url&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;res&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Error: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;✅ Address timeouts explicitly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5000&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="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abort&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;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Request timed out&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;p&gt;✅ Validate input URLs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;validUrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isUri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://example.com&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;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid URL&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;
  
  
  Performance Issues
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Definition
&lt;/h3&gt;

&lt;p&gt;Performance degradation in Node.js often arises from blocking operations, suboptimal queries, and excessive resource consumption, affecting response times and scalability.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/file.txt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Resolution
&lt;/h3&gt;

&lt;p&gt;✅ Favor asynchronous operations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/file.txt&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;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;err&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;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&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;✅ Implement caching with tools like Redis:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;client&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;key&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;err&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="o"&gt;=&amp;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;value&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Cache hit:&lt;/span&gt;&lt;span class="dl"&gt;'&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="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;✅ Monitor performance using tools like &lt;code&gt;clinic.js&lt;/code&gt; and &lt;code&gt;pm2&lt;/code&gt;.&lt;/p&gt;




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

&lt;p&gt;Node.js, while powerful, requires meticulous handling of errors to ensure reliability and performance. Addressing syntax inconsistencies, unhandled promises, and networking failures through best practices fosters robust, scalable applications. Through deliberate debugging and optimization, developers can harness the full potential of Node.js to build sophisticated systems.&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>When Winston with MySQL or CloudWatch Go Wrong: Node.js</title>
      <dc:creator>Rishi Kumar</dc:creator>
      <pubDate>Tue, 07 Jan 2025 11:06:48 +0000</pubDate>
      <link>https://dev.to/mrrishimeena/when-winston-with-mysql-or-cloudwatch-go-wrong-nodejs-5fm</link>
      <guid>https://dev.to/mrrishimeena/when-winston-with-mysql-or-cloudwatch-go-wrong-nodejs-5fm</guid>
      <description>&lt;h3&gt;
  
  
  A Fleeting Glimpse of Smooth Sailing
&lt;/h3&gt;

&lt;p&gt;Sometimes, everything looks perfect on the surface. The Node.js app is snappy, logs are going exactly where you want them, and the performance metrics appear respectable—even under a healthy testing load. That was how my recent experiment began. I hooked up Winston to handle logs, fired up k6 to generate traffic, and kicked back to see if everything would hold together.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Winston + MySQL Puzzle
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Initial Performance Numbers&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;About a 5% dip in app performance under load
&lt;/li&gt;
&lt;li&gt;Over 350,000 requests successfully processed
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Hidden Problem&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only ~70,000 logs made it into the MySQL database
&lt;/li&gt;
&lt;li&gt;The rest were backed up in Node.js streams, waiting to be inserted
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why It’s Terrifying&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A simple crash could wipe out tens of thousands of logs still stuck in memory
&lt;/li&gt;
&lt;li&gt;Critical debugging info would vanish, leaving developers in the dark
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What This Means in Practice&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Even though things looked okay on the front end, Winston-MySQL couldn’t keep up with the log volume. Winston+MySQL, by default, was processing logs one by one through a Node.js stream. Over time, the queue just ballooned, and if anything went wrong, a huge chunk of important log data could simply be lost.&lt;/p&gt;




&lt;h3&gt;
  
  
  Winston + CloudWatch Chaos
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Decent Early Results&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Around a 15% performance hit during moderate loads
&lt;/li&gt;
&lt;li&gt;Logs arrived consistently in CloudWatch at first
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The Domino Effect&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Under heavier traffic, log processing consumed too many resources
&lt;/li&gt;
&lt;li&gt;The logging setup itself crashed, taking the entire node.js service down
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why It’s Risky&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A logging tool that can destabilize the core app is a serious flag
&lt;/li&gt;
&lt;li&gt;Production environments need stability—tolerating a logging-induced crash is out of the question&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Lessons Learned&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
CloudWatch felt fine at lower volumes but quickly turned into a showstopper under heavier traffic. Instead of giving us reliable insights, it caused resource contention that brought the house down.&lt;/p&gt;




&lt;h3&gt;
  
  
  Rethinking the Logging Approach
&lt;/h3&gt;

&lt;p&gt;Both Winston-MySQL and Winston-CloudWatch have their places, but these examples highlight how important it is to choose the right logging strategy for your specific load. Your logs should be fast, reliable, and never the source of crashes or major bottlenecks.  &lt;/p&gt;

&lt;p&gt;No one wants to stay up at night worrying about incomplete logs or random crashes. Logging might not be the flashiest part of the application, but it’s one of the most critical. And when it’s done poorly, it can have a bigger impact on performance and reliability than almost anything else in your stack.&lt;/p&gt;

</description>
      <category>node</category>
      <category>opensource</category>
      <category>devchallenge</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>The Logging Tool You Need for Logs, Errors, and Collaboration in Node.js</title>
      <dc:creator>Rishi Kumar</dc:creator>
      <pubDate>Mon, 30 Dec 2024 07:18:07 +0000</pubDate>
      <link>https://dev.to/mrrishimeena/the-only-tool-you-need-for-logs-errors-and-collaboration-nodejs-15l7</link>
      <guid>https://dev.to/mrrishimeena/the-only-tool-you-need-for-logs-errors-and-collaboration-nodejs-15l7</guid>
      <description>&lt;p&gt;Errsole is not just a logging library but an &lt;strong&gt;enhanced logger with built-in visualization and error management features&lt;/strong&gt;. It stands out by combining logging, error notifications, and a web-based dashboard for managing and analyzing logs efficiently. &lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Why Use Errsole.js&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Single-Module Simplicity&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Errsole.js combines logging, error alert, and visualization into one package, reducing the need for multiple tools.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Web Dashboard&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A built-in web dashboard allows you to view, filter, and search logs without third-party tools. &lt;/li&gt;
&lt;li&gt;Features like team management and secure access make it ideal for collaborative debugging.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Flexible Storage&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Offers support for SQLite, MySQL, PostgreSQL, and MongoDB for storing logs.&lt;/li&gt;
&lt;li&gt;You can customize log retention policies, ensuring suitability for both local development and production environments.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Critical Error Notifications&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Alerts for critical errors, sent through channels like email or Slack, help in reducing response times.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;High Performance&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Benchmarks show it handles 70,000-90,000 more requests per minute compared to traditional setups like Elasticsearch and CloudWatch.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Custom Logging Features&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enhanced logging capabilities include custom levels (e.g., &lt;code&gt;error&lt;/code&gt;, &lt;code&gt;info&lt;/code&gt;, &lt;code&gt;debug&lt;/code&gt;) and metadata support for better context in logs.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Integration with Popular Tools&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Works seamlessly with tools like Winston and offers an easy setup for integrating existing logging infrastructure.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Open Source and Free&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fully open-source with no licensing costs.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Errsole.js vs Other Libraries&lt;/strong&gt;
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Errsole.js&lt;/th&gt;
&lt;th&gt;Winston&lt;/th&gt;
&lt;th&gt;Pino&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Built-in Dashboard&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No (needs external tools)&lt;/td&gt;
&lt;td&gt;No (needs external tools)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Error Notifications&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Custom Logging&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Advanced (metadata, levels)&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Storage Options&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Multiple DBs, SQLite, MongoDB&lt;/td&gt;
&lt;td&gt;Custom&lt;/td&gt;
&lt;td&gt;Custom&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Performance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Integration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Built-in (e.g., Winston)&lt;/td&gt;
&lt;td&gt;Extensive (setup required)&lt;/td&gt;
&lt;td&gt;Setup required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Team Management&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;When to Use Errsole.js&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Small Teams&lt;/strong&gt;: Perfect for teams needing an all-in-one solution without setting up complex infrastructures.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High-Performance Apps&lt;/strong&gt;: Ideal for handling high traffic while maintaining logging efficiency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Collaborative Debugging&lt;/strong&gt;: Offers team-specific access and metadata-rich logs for shared troubleshooting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Production Monitoring&lt;/strong&gt;: Combines real-time error notifications with robust storage options.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;How to Get Started with Errsole.js&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Installation&lt;/strong&gt;:
&lt;/h4&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;errsole
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;Setup&lt;/strong&gt;:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;errsole&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;errsole&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;ErrsoleSQLite&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;errsole-sqlite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;errsole&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;storage&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;ErrsoleSQLite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/path/to/logs.sqlite&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Logging with Errsole.js!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;Access the Dashboard&lt;/strong&gt;:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Open your browser and visit &lt;code&gt;http://localhost:8001/&lt;/code&gt; or your configured server URL.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Custom Logging&lt;/strong&gt;:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;errsole&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="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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Application started successfully&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;errsole&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1234&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User action failed&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;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;delete&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;In production environments, where centralized log storage is critical, Errsole offers multiple storage options to fit your needs:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/errsole/errsole.js/blob/master/docs/mongodb-storage.md" rel="noopener noreferrer"&gt;Errsole with MongoDB&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/errsole/errsole.js/blob/master/docs/mysql-storage.md" rel="noopener noreferrer"&gt;Errsole with MySQL&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/errsole/errsole.js/blob/master/docs/postgresql-storage.md" rel="noopener noreferrer"&gt;Errsole with PostgreSQL&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Errsole.js is not just a logging library; it’s a comprehensive solution for error management and log visualization. It is particularly beneficial for modern Node.js applications where performance, collaboration, and reliability are key.&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>opensource</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Building a Simple Email-Open Tracking System for Your Gmail</title>
      <dc:creator>Rishi Kumar</dc:creator>
      <pubDate>Fri, 27 Dec 2024 13:21:04 +0000</pubDate>
      <link>https://dev.to/mrrishimeena/building-a-simple-email-open-tracking-system-for-your-gmail-5d22</link>
      <guid>https://dev.to/mrrishimeena/building-a-simple-email-open-tracking-system-for-your-gmail-5d22</guid>
      <description>&lt;p&gt;In today’s email landscape, marketing platforms typically bundle “open” or “read” tracking by default. But what if you want a &lt;strong&gt;personal&lt;/strong&gt; tracking pixel system—one where you can see open logs for certain one-off emails you send from &lt;strong&gt;Gmail&lt;/strong&gt;?&lt;/p&gt;




&lt;p&gt;GitHub Link : &lt;a href="https://github.com/DevSpeaks/mail-tracker" rel="noopener noreferrer"&gt;Mail Tracker&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Roll your own &lt;strong&gt;Node.js + Express + EJS + SQLite&lt;/strong&gt; app:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Generates 1×1 pixels&lt;/strong&gt; tied to unique IDs,
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logs open events&lt;/strong&gt; (date/time, IP, user agent),
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Serves a real .png file&lt;/strong&gt; so Gmail/other clients see a standard image.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You’ll get a lightweight dashboard showing which pixels were created, plus the logs of open events. While this won't be 100% foolproof (due to image blocking or proxies like GoogleImageProxy), it’s a fun, educational way to see basic open-tracking in action for your personal emails.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Node.js&lt;/strong&gt; installed locally.&lt;/li&gt;
&lt;li&gt;Some familiarity with &lt;strong&gt;Express&lt;/strong&gt; (for routing).&lt;/li&gt;
&lt;li&gt;A willingness to tinker with &lt;strong&gt;EJS&lt;/strong&gt; (template engine) and &lt;strong&gt;SQLite&lt;/strong&gt; for storing data.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip&lt;/strong&gt;: If you want other people (external recipients) to open your pixel, your server &lt;strong&gt;must&lt;/strong&gt; be accessible to the outside world. Hosting on a platform like &lt;strong&gt;Render&lt;/strong&gt;, &lt;strong&gt;Heroku&lt;/strong&gt;, or using a tunnel service (e.g. &lt;strong&gt;ngrok&lt;/strong&gt; or &lt;strong&gt;localtunnel&lt;/strong&gt;) can help.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  2. Core Concepts
&lt;/h2&gt;

&lt;h3&gt;
  
  
  2.1. Tracking Pixel
&lt;/h3&gt;

&lt;p&gt;A “tracking pixel” is just a hidden image in your email. If the recipient’s client loads images, your server sees an HTTP request for that 1×1 PNG (or GIF).&lt;/p&gt;

&lt;h3&gt;
  
  
  2.2. Logging Opens
&lt;/h3&gt;

&lt;p&gt;When someone (or some proxy) fetches &lt;code&gt;/tracker/&amp;lt;pixel_id&amp;gt;.png&lt;/code&gt;, you record:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Timestamp&lt;/strong&gt; (when it was fetched),&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IP address&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User agent&lt;/strong&gt; (might show &lt;code&gt;GoogleImageProxy&lt;/code&gt; for Gmail, indicating the real user’s IP is masked).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2.3. Gmail &amp;amp; Image Proxies
&lt;/h3&gt;

&lt;p&gt;Modern Gmail proxies images (served from &lt;code&gt;ggpht.com&lt;/code&gt; or similar). This means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You won’t see the &lt;strong&gt;recipient’s&lt;/strong&gt; real IP address.&lt;/li&gt;
&lt;li&gt;Gmail often fetches the pixel &lt;strong&gt;once&lt;/strong&gt; and caches it, so subsequent opens might not appear as a new log.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Despite these limitations, you can still see &lt;strong&gt;if/when&lt;/strong&gt; the image was first fetched—often close to when the user opened your email for the first time.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Our Simple Node App
&lt;/h2&gt;

&lt;h3&gt;
  
  
  3.1. Project Setup
&lt;/h3&gt;

&lt;p&gt;Create a folder (say &lt;code&gt;mail-tracker&lt;/code&gt;), then:&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;cd &lt;/span&gt;mail-tracker
npm init &lt;span class="nt"&gt;-y&lt;/span&gt;
npm &lt;span class="nb"&gt;install &lt;/span&gt;express ejs sqlite3 uuid
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You’ll end up with a &lt;code&gt;package.json&lt;/code&gt; that references these dependencies. Next:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create&lt;/strong&gt; a &lt;code&gt;public/images&lt;/code&gt; folder with a &lt;strong&gt;1×1 transparent PNG&lt;/strong&gt; named &lt;code&gt;pixel.png&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create&lt;/strong&gt; two EJS files in a &lt;code&gt;views&lt;/code&gt; folder: &lt;code&gt;index.ejs&lt;/code&gt; (dashboard) and &lt;code&gt;logs.ejs&lt;/code&gt; (show logs).&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  3.2. &lt;code&gt;app.js&lt;/code&gt; (Main Server File)
&lt;/h3&gt;

&lt;p&gt;Below is a simplified excerpt. It:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stores pixel data in &lt;strong&gt;SQLite&lt;/strong&gt; (&lt;code&gt;mail-tracker.db&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Serves&lt;/strong&gt; static files (so &lt;code&gt;pixel.png&lt;/code&gt; can be loaded if we want).&lt;/li&gt;
&lt;li&gt;Has a &lt;code&gt;/tracker/:id.png&lt;/code&gt; route that logs an open and sends back the real &lt;code&gt;pixel.png&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&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;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;v4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;uuidv4&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;uuid&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;sqlite3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sqlite3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;verbose&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;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;app&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;view engine&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="s1"&gt;ejs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlencoded&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;extended&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;

&lt;span class="c1"&gt;// Serve static files from /public&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;static&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;public&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;

&lt;span class="c1"&gt;// Initialize SQLite&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;sqlite3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mail-tracker.db&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;err&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="c1"&gt;// Create tables if not existing&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Middleware to get baseUrl for EJS&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&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;protocol&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;protocol&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;host&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;host&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;locals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;baseUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;protocol&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;://&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Dashboard: list all pixels&lt;/span&gt;
&lt;span class="nx"&gt;app&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&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;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&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="c1"&gt;// SELECT * FROM pixels ...&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;index&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;pixels&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Create pixel&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/create&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;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&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;pixelId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;uuidv4&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="c1"&gt;// Insert pixel into DB&lt;/span&gt;
  &lt;span class="c1"&gt;// redirect to '/'&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// The tracker route&lt;/span&gt;
&lt;span class="nx"&gt;app&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/tracker/:id.png&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;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&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="c1"&gt;// Check pixel ID, log open in DB&lt;/span&gt;
  &lt;span class="c1"&gt;// Serve the real 'pixel.png'&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;public&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="s1"&gt;images&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="s1"&gt;pixel.png&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="c1"&gt;// View logs&lt;/span&gt;
&lt;span class="nx"&gt;app&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/logs/:id&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;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&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="c1"&gt;// SELECT logs from DB for that pixel&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;logs&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;pixel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;logs&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Start server&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PORT&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="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="s2"&gt;`Listening on &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3.3. &lt;code&gt;index.ejs&lt;/code&gt; (Dashboard)
&lt;/h3&gt;

&lt;p&gt;Shows a form to create a new pixel plus a table listing existing ones:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Mail Tracker - Dashboard&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Mail Tracker - Dashboard&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Create a New Tracking Pixel&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"/create"&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"POST"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;Pixel Name (optional):&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Create Pixel&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Existing Pixels&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- For each pixel, show tracker URL like: baseUrl/tracker/PIXEL_ID.png --&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- Link to logs page to see open events --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3.4. &lt;code&gt;logs.ejs&lt;/code&gt; (Show Logs)
&lt;/h3&gt;

&lt;p&gt;Lists each open event (time, IP, user agent). We can format the time, group rapid logs with color, etc.:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Mail Tracker - Logs&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Logs for &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%=&lt;/span&gt; &lt;span class="na"&gt;pixel.name&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Created At: &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%=&lt;/span&gt; &lt;span class="na"&gt;pixel.createdAt&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Open Events&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"font-style: italic;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      You may see extra logs if bots (for example, GoogleImageProxy via ggpht.com) or the email client repeatedly load the image.
      Check each log’s timestamp to distinguish real user opens from proxy fetches.
    &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;table&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;thead&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;&lt;/span&gt;Time&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;&lt;/span&gt;IP&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;&lt;/span&gt;User-Agent&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/thead&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;tbody&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%&lt;/span&gt; &lt;span class="err"&gt;//&lt;/span&gt; &lt;span class="na"&gt;For&lt;/span&gt; &lt;span class="na"&gt;each&lt;/span&gt; &lt;span class="na"&gt;log&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="na"&gt;show&lt;/span&gt; &lt;span class="na"&gt;the&lt;/span&gt; &lt;span class="na"&gt;local-time&lt;/span&gt; &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="na"&gt;IP&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="na"&gt;userAgent&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="na"&gt;etc.&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/tbody&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/table&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. Embedding into Gmail
&lt;/h2&gt;

&lt;h3&gt;
  
  
  4.1. Copy the Tracker URL
&lt;/h3&gt;

&lt;p&gt;Once your server is running publicly, your pixel has a URL like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://myapp.example.com/tracker/1234abcd-....png
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or, if you’re using a local tunnel:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://random.loca.lt/tracker/1234abcd-....png
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.2. Insert Photo by URL
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Compose&lt;/strong&gt; a new email in Gmail.
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Insert photo&lt;/strong&gt; → &lt;strong&gt;Web Address (URL)&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;Paste the &lt;strong&gt;Tracker URL&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;If Gmail says “We can’t find or access that image,” you can still insert and send.
&lt;/li&gt;
&lt;li&gt;When the recipient opens (and images are enabled), Gmail loads (or caches) that image, and your logs record an event.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Because Gmail proxies images, the request will likely come from Google servers (e.g., &lt;code&gt;GoogleImageProxy/ggpht.com&lt;/code&gt;). You won’t get the real recipient’s IP. But you do see &lt;strong&gt;when&lt;/strong&gt; the pixel was fetched—often correlating with a user open.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  5. Understanding “Extra Logs” &amp;amp; Proxy Behavior
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Multiple Logs&lt;/strong&gt;: If Gmail or another client refreshes or re-fetches the image, or if the user reopens the message, you’ll see multiple entries. Some might be within &lt;strong&gt;seconds&lt;/strong&gt; of each other, triggered by background processes or spam filters.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User Agent&lt;/strong&gt;: You might see &lt;code&gt;GoogleImageProxy&lt;/code&gt; instead of a real browser’s user agent. This is normal for Gmail. Other clients, like Apple Mail or Outlook, might show more direct info.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IP&lt;/strong&gt;: Because of proxies, you’ll usually see a Google IP range, not the actual recipient’s IP. That’s a privacy measure.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  6. Limitations &amp;amp; Future Enhancements
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Image-Blocking&lt;/strong&gt;: If the recipient’s mail client blocks images by default, your pixel is never loaded. So you won’t see an open event.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Caching&lt;/strong&gt;: Gmail especially caches images. Subsequent opens may not trigger a new request.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No IP / Location&lt;/strong&gt;: With proxies, you don’t see the real user’s IP or location.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unique Query Params&lt;/strong&gt;: If you want to track individual recipients, create a separate pixel for each person or append query strings like &lt;code&gt;?user=john@example.com&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  7. Why Build a Personal Tracker?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Educational&lt;/strong&gt;: Learn how open tracking works under the hood.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Privacy&lt;/strong&gt;: You control your own data, rather than trusting a third-party marketing provider.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debugging&lt;/strong&gt;: If you want to see if a friend/client is reading your email, or simply confirm some one-time outreach was opened.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(Always be mindful of &lt;strong&gt;legal&lt;/strong&gt; or &lt;strong&gt;ethical&lt;/strong&gt; constraints in your region and among your contacts.)&lt;/p&gt;




&lt;h2&gt;
  
  
  8. Conclusion
&lt;/h2&gt;

&lt;p&gt;Running your own open-tracking service can be a fun side project—especially to see how &lt;strong&gt;Gmail&lt;/strong&gt; or other providers handle images. You’ll quickly discover that &lt;strong&gt;GoogleImageProxy&lt;/strong&gt; can mask real IP addresses, and not every open is captured if images are off. Nonetheless, for personal use, it’s a neat way to see open events in real time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Steps&lt;/strong&gt; Recap:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Build&lt;/strong&gt; a Node.js + Express server.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generate&lt;/strong&gt; unique IDs/pixels.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Log&lt;/strong&gt; requests to &lt;code&gt;/tracker/:id.png&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Serve&lt;/strong&gt; a legitimate &lt;code&gt;.png&lt;/code&gt; file.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Embed&lt;/strong&gt; the pixel in your Gmail messages.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check&lt;/strong&gt; your logs for open events (and interpret carefully).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That’s it—your own personal email tracking system. Once you see it in action, you’ll have a deeper appreciation for how major mailing platforms do open tracking at scale and why they run into the same limitations of caching and image-blocking.&lt;/p&gt;




&lt;p&gt;GitHub Link : &lt;a href="https://github.com/DevSpeaks/mail-tracker" rel="noopener noreferrer"&gt;Mail Tracker&lt;/a&gt;&lt;/p&gt;

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