<?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: Moesif Staff</title>
    <description>The latest articles on DEV Community by Moesif Staff (@moesif_staff).</description>
    <link>https://dev.to/moesif_staff</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%2F2848407%2Fe95a2755-843a-44d0-ac7e-bd00f62b54b3.png</url>
      <title>DEV Community: Moesif Staff</title>
      <link>https://dev.to/moesif_staff</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/moesif_staff"/>
    <language>en</language>
    <item>
      <title>11 Most Popular Tools for Logging and Monitoring API Calls</title>
      <dc:creator>Moesif Staff</dc:creator>
      <pubDate>Thu, 27 Mar 2025 17:58:44 +0000</pubDate>
      <link>https://dev.to/moesif/11-most-popular-tools-for-logging-and-monitoring-api-calls-5f06</link>
      <guid>https://dev.to/moesif/11-most-popular-tools-for-logging-and-monitoring-api-calls-5f06</guid>
      <description>&lt;p&gt;Monitoring and API logging, facilitated by various API monitoring tools, is no longer a nice-to-have – for many API providers, it has become a key part of ensuring growth and success in the ever-evolving API landscape. There are as many API monitoring tool providers as there are approaches to this topic, but we’ve gathered together a list of the top 11 in the market today. But first, let's take a look at a few things to consider.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is API Monitoring?
&lt;/h2&gt;

&lt;p&gt;API monitoring is the process of continuously tracking and analyzing the performance, functionality, and reliability of Application Programming Interfaces (APIs). It involves monitoring API calls, requests, and responses to ensure they are functioning correctly and efficiently. A well-structured API log includes timestamps, HTTP methods, endpoints accessed, request and response details, client information, and latency. By keeping a close eye on these interactions, developers can proactively identify and address issues, minimizing downtime and optimizing overall efficiency. Real-time insights into API performance and reliability enable quick troubleshooting and data-driven decision-making, ensuring that APIs deliver a seamless user experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key API Metrics to Monitor
&lt;/h2&gt;

&lt;p&gt;Monitoring key API metrics is crucial for ensuring the performance, reliability, and security of APIs. Some of the essential metrics to keep an eye on include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Response Time&lt;/strong&gt;: The time taken by an API to process a request and return a response. Lower response times indicate better performance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Error Rate&lt;/strong&gt;: The number of API calls resulting in non-200 status codes. A high error rate can signal underlying issues that need immediate attention. Error logs provide detailed information about exceptions and errors encountered during API operations, including error messages and stack traces.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Uptime&lt;/strong&gt;: The percentage of time a service is available. High uptime is critical for maintaining user trust and satisfaction.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CPU Usage&lt;/strong&gt;: The percentage of CPU resources used by an application. Monitoring CPU usage helps in identifying performance bottlenecks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Memory Usage&lt;/strong&gt;: The amount of memory used by an application. Efficient memory usage is vital for optimal performance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Endpoint Performance&lt;/strong&gt;: The performance of specific API endpoints. Monitoring individual endpoints helps in pinpointing issues.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;API Calls per Minute&lt;/strong&gt;: The number of API calls made per minute. This metric helps in understanding the load on the API.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Log Data&lt;/strong&gt;: The data generated by API logs, including request and response data. Analyzing log data provides deep insights into API interactions.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  API Logging and Monitoring Best Practices
&lt;/h2&gt;

&lt;p&gt;Effective API logging and monitoring are critical for maintaining robust API performance. Here are some best practices to follow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Log All API Requests and Responses&lt;/strong&gt;: Ensure that every API request and response is logged for comprehensive tracking.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use a Centralized Logging System&lt;/strong&gt;: Collect and manage log data in a centralized system for easier analysis and troubleshooting.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Monitor API Performance and Reliability in Real-Time&lt;/strong&gt;: Real-time monitoring helps in quickly identifying and addressing issues.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Set Up Alerts and Notifications for Critical Issues&lt;/strong&gt;: Configure alerts for critical issues to ensure prompt response and resolution.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use Log Data to Troubleshoot Issues and Optimize Performance&lt;/strong&gt;: Analyze log data to identify and fix performance bottlenecks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Implement Secure Logging Practices&lt;/strong&gt;: Protect sensitive data by following secure logging practices.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Regularly Review and Refine Logging and Monitoring Practices&lt;/strong&gt;: Continuously improve your logging and monitoring strategies to keep up with evolving needs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use Structured Logs&lt;/strong&gt;: Structured logs use a uniform format across all entries, facilitating easier querying and analysis.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Real-Time Monitoring and API Observability
&lt;/h2&gt;

&lt;p&gt;Real-time monitoring is essential for achieving API observability, providing instant insights into API performance and reliability. By analyzing log data and metrics in real-time, developers can quickly detect and respond to issues, optimizing API performance and reducing downtime. Real-time monitoring enables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Quick Issue Detection and Response&lt;/strong&gt;: Immediate identification of problems allows for prompt resolution.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Optimized API Performance and Reliability&lt;/strong&gt;: Continuous monitoring helps in maintaining high performance and reliability.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Improved User Experience&lt;/strong&gt;: Minimizing downtime and performance issues leads to a better user experience.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data-Driven Decision Making&lt;/strong&gt;: Real-time insights support informed decision-making.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Integration with Other Observability Tools&lt;/strong&gt;: Seamless integration with other tools enhances overall observability.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Choosing the Right API Monitoring Tool
&lt;/h2&gt;

&lt;p&gt;Selecting the right API monitoring tool is crucial for effective API monitoring. Consider the following factors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Comprehensive Visibility&lt;/strong&gt;: The tool should offer complete visibility into API performance and reliability.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Real-Time Monitoring&lt;/strong&gt;: Ensure the tool provides real-time monitoring and analysis of log data and metrics.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Customizable Alerts&lt;/strong&gt;: Look for tools that offer customizable alerts and notifications for critical issues.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Integration&lt;/strong&gt;: The tool should integrate well with other observability tools and processes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scalability&lt;/strong&gt;: Choose a tool that can scale to meet growing API demands.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Security&lt;/strong&gt;: The tool should implement secure logging practices to protect sensitive data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;User Experience&lt;/strong&gt;: A user-friendly interface is essential for easy monitoring and analysis.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By considering these factors, developers can choose the right API monitoring tool for their needs, ensuring effective API monitoring and observability.&lt;/p&gt;

&lt;h2&gt;
  
  
  1 - Moesif
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.moesif.com/features/api-logs?utm_campaign=Int-site&amp;amp;utm_source=blog&amp;amp;utm_medium=body-cta&amp;amp;utm_content=most-popular-tools-for-logging" rel="noopener noreferrer"&gt;Moesif&lt;/a&gt; is a powerful, feature-rich solution for API monitoring and tracking. Moesif also provides detailed insights into API transactions, capturing information about API requests and responses to ensure quality and performance. Rather than synthetic monitoring, Moesif provides real user monitoring, giving businesses the ability to dive into their API performance and API call data. By combining real-time event logging with product analytics (including API endpoint analysis, API testing, and API gateway integration), monetization systems (including quotas, governance, and metered billing), and alerts (both real-time and behavioral, as well as API security), Moesif promises to unlock better revenue performance, improve user retention, and generate unprecedented insight and awareness across your API.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Provides powerful context and deep introspection through unlocked application-layer visibility&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Easy to set up across a variety of systems and implementations&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Drawbacks
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Governance Rules only available on enterprise tier&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2 - Prometheus
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://prometheus.io/docs/prometheus/latest/management_api/" rel="noopener noreferrer"&gt;Prometheus&lt;/a&gt; is a widely-adopted open source monitoring solution. Prometheus also excels in infrastructure monitoring, helping to ensure system reliability and performance. It has generated quite a following due to its developer outreach backing, with ample documentation, blogs, video content, etc. That being said, Prometheus was designed to generate insights based on metrics, and thus is often considered more an “insights” solution than a “logging” one. Logs are stored locally and are then pointed to by Prometheus when an issue is detected per the metrics – for this reason, users typically use Prometheus in addition to an API logging solution for remote hosting, which makes Prometheus – at least for a subset of users – a half solution for monitoring API products.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Well-documented and easy to implement&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ample insights generated from small amounts of data&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Drawbacks
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Lack of native cloud logging support&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;May not be a complete solve for many users&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3 - Sematext
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://sematext.com/" rel="noopener noreferrer"&gt;Sematext&lt;/a&gt; offers a very popular solution in Sematext Logs. Sematext Logs supports the creation of detailed log entries, capturing essential data for troubleshooting and performance monitoring. Sematext positions their offering as a Log Management-as-a-Service model, supporting the exfiltration of API logs from containers, infrastructure, applications, etc. It facilitates this by supporting Syslog or the Elasticsearch API, which opens it to a wide range of implementations. Because it supports these solutions, you can use Sematext natively, bypassing more expensive options which require third party solutions for performance monitoring.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Wide support for systems and applications&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cheaper to use than many other solutions&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Drawbacks
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Requires using either Syslog or Elasticsearch, which can be limiting in some situations&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Requires buying into the “as-a-Service” dynamic&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4 - Papertrail
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.papertrail.com/" rel="noopener noreferrer"&gt;Papertrail&lt;/a&gt; is a logging solution from SolarWinds Cloud, a Software-as-a-Service solution. Each log entry in Papertrail captures critical elements like timestamps and request details, aiding in diagnosing issues. Papertrail allows for a large amount of customizability, and because it’s part of what is typically a holistic solution, it offers substantial cross-service and cross-database API logging that is often much slower and more expensive in other solutions. The drawback, of course, is that Papertrail works best as part of the SolarWinds Cloud service – and if you’re not using that service, your experience may not be as good as it could be with other open-source or free software solutions. If you currently are a SolarWinds customer, the best solution for your API monitor may be Papertrail.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Highly customizable&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cross-service and cross-database&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Drawbacks
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Part of a suite of offerings that do better as part of SolarWinds Cloud&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Not robustly open-source&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5 - Checkly
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.checklyhq.com/" rel="noopener noreferrer"&gt;Checkly&lt;/a&gt; is a very new player in the logging software scene, but it brings a lot to the table. Checkly provides insights into key metrics such as response times and error rates, crucial for evaluating API performance. Beyond its powerful synthetic monitoring and API logging, it also allows for deep contextual inspection, diving into payload, responses, headers, and more. Latency, which refers to the time delay between API request and response time, is another critical metric Checkly helps to monitor. This amount of logging and API analytics provide a great amount of context and can improve your visibility quite significantly through application performance monitoring. Pricing is relatively simple and follows a freemium model – that being said, more complex environments might quickly run above the relatively modest 10,000 API calls in the free plan, and the custom plan may have higher costs compared to something that is self-hosted.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Relatively inexpensive&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Provides high context&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Drawbacks
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Very new player, so not as proven&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Limited freemium offering&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  6 - Datadog
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.datadoghq.com/" rel="noopener noreferrer"&gt;Datadog&lt;/a&gt; bills itself as an observability platform, offering a relatively feature-complete solution for logging, website monitoring, application monitoring, and reporting for REST API-based products and beyond. Datadog's suite of monitoring tools provides real-time insights into API performance and reliability. It allows users to set specific metric-based rules to generate alerts across channels like Slack, SMS, email, etc. Datadog is relatively cheap, which is a big reason it has seen good adoption across the board – that being said, it doesn’t provide as much detail as some other solutions in the marketplace, making it a good generalist middle-of-the-road API management solution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Feature-complete compared to others on this list&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Relatively cheap to deploy&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Drawbacks
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Limited detail compared to other solutions&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  7 - Sauce Labs
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://saucelabs.com/" rel="noopener noreferrer"&gt;Sauce Labs&lt;/a&gt; used to be called API Fortress, and under that name, it generated a bit of a reputation as a cloud-based REST API monitoring solution. Setting up Sauce Labs for monitoring involves establishing secure connections to ensure data integrity and security. Sauce Labs continues this success by providing testing, monitoring, and reporting, but for those looking principally for API log tooling, Sauce Labs can seem a bit too feature-complete. Ultimately the use case for Sauce Labs is a bit of column A and column B – if you want to collect API logs for the purpose of generating reports and insights, Sauce Labs is a great solution. If you want to log to just log, this might be another in the column of “too good for what you need”.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Very mature in the market&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Widely adopted giving a huge user community&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Drawbacks
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Perhaps too mature for those looking only for logging&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A bit too general for specific use cases&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  8 - Amazon CloudWatch
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://aws.amazon.com/cloudwatch/" rel="noopener noreferrer"&gt;Amazon CloudWatch&lt;/a&gt; brings the proven logging and monitoring approaches on offer from Amazon. Amazon CloudWatch is one of the most flexible API monitoring tools available, offering robust logging and monitoring capabilities. This solution is relatively robust, but the main selling point is in the pricing model – CloudWatch is very flexible, offering pay-as-you-go, which allows for easy scaling. That being said, the solution is tooled specifically for the AWS API gateway, which makes it a hard sell to anyone not utilizing AWS systems. Because of the usage based nature of CloudWatch’s payment structure understanding the performance metric that eat your budget can help guide the decision to use CloudWatch for uptime monitoring or synthetic API monitoring.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Relatively efficient and feature rich&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pay-as-you-go pricing makes it flexible&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Drawbacks
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Tooled for AWS specifically, which may exclude it from some stacks&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  9 - AppDynamics
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.appdynamics.com/" rel="noopener noreferrer"&gt;AppDynamics&lt;/a&gt; is particularly powerful and is backed by the Cisco product offering. It offers real-time data visualization and analysis, and provides relatively robust solutions like resource waterfalls to show the impact of each element of the API service in the overall efficiency and user experience. AppDynamics provides comprehensive monitoring for any application programming interface, ensuring optimal performance and reliability. That being said, this is another offering that is run by a corporate entity, and its quite expensive – for many developers, this might be a huge negative that is difficult to overcome no matter how beautiful the visualizations are in practice.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Backed by Cisco and its mature product offering&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Real-time data visualization&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Drawbacks
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Not open source and corporate in nature&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Quite expensive&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  10 - Uptrends
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.uptrends.com/" rel="noopener noreferrer"&gt;Uptrends&lt;/a&gt; offers a robust multi-step logging and API monitoring tool, selling itself as a logging and alerting system first and foremost. Uptrends offers “Private Checkpoints”, a solution that unlocks testing behind private networks and firewalls. Uptrends is very clearly leaning on its solution as a “problem resolution” one, with one area of the site boasting “Yesterday we detected 332k errors. How's your site doing?”. The main drawback here is that Uptrends is very clearly selling itself as an analysis tool rather than just an API log tool. For developers looking for logging – and just logging – Uptrends is too far down the monitoring path.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Robust logging and monitoring&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Works on private systems and networks&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Drawbacks
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Monitoring-heavy makes logging a second thought&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Provides ample analysis which may just be a cost increase vs. a utility increase for some stacks&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  11 - Graphite
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://graphiteapp.org/" rel="noopener noreferrer"&gt;Graphite&lt;/a&gt; is an open source monitoring and logging system that utilizes a push-based design architecture. What this means is that Graphite allows services to push their API logs into a component called Graphite Carbon, which is then stored in a database for later deep introspection and transformation. Prometheus, another open-source monitoring toolkit designed for cloud-native applications, is often used alongside Graphite for enhanced monitoring capabilities. Graphite's main selling point is its easy deployment through its native Synthesize product, an automated installation and configuration system which promises to get users up and running with minimal headache.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Open source and feature-rich&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Easy deployment&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Drawbacks
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Depends on its own solutions - may be stack limiting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We hope this list has helped you see the offerings in the current marketplace. Please note that this list is not exhaustive – nonetheless, it provides a good overview of the most common solutions available today! Feel free to let us know if there are more solutions you'd love included in this list.&lt;/p&gt;

</description>
      <category>api</category>
      <category>monitoring</category>
      <category>tooling</category>
      <category>developers</category>
    </item>
    <item>
      <title>11 Most Popular Tools for Logging and Monitoring API Calls</title>
      <dc:creator>Moesif Staff</dc:creator>
      <pubDate>Thu, 27 Mar 2025 17:58:44 +0000</pubDate>
      <link>https://dev.to/moesif/11-most-popular-tools-for-logging-and-monitoring-api-calls-561e</link>
      <guid>https://dev.to/moesif/11-most-popular-tools-for-logging-and-monitoring-api-calls-561e</guid>
      <description>&lt;p&gt;Monitoring and API logging, facilitated by various API monitoring tools, is no longer a nice-to-have – for many API providers, it has become a key part of ensuring growth and success in the ever-evolving API landscape. There are as many API monitoring tool providers as there are approaches to this topic, but we’ve gathered together a list of the top 11 in the market today. But first, let's take a look at a few things to consider.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is API Monitoring?
&lt;/h2&gt;

&lt;p&gt;API monitoring is the process of continuously tracking and analyzing the performance, functionality, and reliability of Application Programming Interfaces (APIs). It involves monitoring API calls, requests, and responses to ensure they are functioning correctly and efficiently. A well-structured API log includes timestamps, HTTP methods, endpoints accessed, request and response details, client information, and latency. By keeping a close eye on these interactions, developers can proactively identify and address issues, minimizing downtime and optimizing overall efficiency. Real-time insights into API performance and reliability enable quick troubleshooting and data-driven decision-making, ensuring that APIs deliver a seamless user experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key API Metrics to Monitor
&lt;/h2&gt;

&lt;p&gt;Monitoring key API metrics is crucial for ensuring the performance, reliability, and security of APIs. Some of the essential metrics to keep an eye on include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Response Time&lt;/strong&gt;: The time taken by an API to process a request and return a response. Lower response times indicate better performance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Error Rate&lt;/strong&gt;: The number of API calls resulting in non-200 status codes. A high error rate can signal underlying issues that need immediate attention. Error logs provide detailed information about exceptions and errors encountered during API operations, including error messages and stack traces.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Uptime&lt;/strong&gt;: The percentage of time a service is available. High uptime is critical for maintaining user trust and satisfaction.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CPU Usage&lt;/strong&gt;: The percentage of CPU resources used by an application. Monitoring CPU usage helps in identifying performance bottlenecks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Memory Usage&lt;/strong&gt;: The amount of memory used by an application. Efficient memory usage is vital for optimal performance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Endpoint Performance&lt;/strong&gt;: The performance of specific API endpoints. Monitoring individual endpoints helps in pinpointing issues.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;API Calls per Minute&lt;/strong&gt;: The number of API calls made per minute. This metric helps in understanding the load on the API.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Log Data&lt;/strong&gt;: The data generated by API logs, including request and response data. Analyzing log data provides deep insights into API interactions.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  API Logging and Monitoring Best Practices
&lt;/h2&gt;

&lt;p&gt;Effective API logging and monitoring are critical for maintaining robust API performance. Here are some best practices to follow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Log All API Requests and Responses&lt;/strong&gt;: Ensure that every API request and response is logged for comprehensive tracking.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use a Centralized Logging System&lt;/strong&gt;: Collect and manage log data in a centralized system for easier analysis and troubleshooting.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Monitor API Performance and Reliability in Real-Time&lt;/strong&gt;: Real-time monitoring helps in quickly identifying and addressing issues.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Set Up Alerts and Notifications for Critical Issues&lt;/strong&gt;: Configure alerts for critical issues to ensure prompt response and resolution.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use Log Data to Troubleshoot Issues and Optimize Performance&lt;/strong&gt;: Analyze log data to identify and fix performance bottlenecks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Implement Secure Logging Practices&lt;/strong&gt;: Protect sensitive data by following secure logging practices.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Regularly Review and Refine Logging and Monitoring Practices&lt;/strong&gt;: Continuously improve your logging and monitoring strategies to keep up with evolving needs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use Structured Logs&lt;/strong&gt;: Structured logs use a uniform format across all entries, facilitating easier querying and analysis.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Real-Time Monitoring and API Observability
&lt;/h2&gt;

&lt;p&gt;Real-time monitoring is essential for achieving API observability, providing instant insights into API performance and reliability. By analyzing log data and metrics in real-time, developers can quickly detect and respond to issues, optimizing API performance and reducing downtime. Real-time monitoring enables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Quick Issue Detection and Response&lt;/strong&gt;: Immediate identification of problems allows for prompt resolution.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Optimized API Performance and Reliability&lt;/strong&gt;: Continuous monitoring helps in maintaining high performance and reliability.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Improved User Experience&lt;/strong&gt;: Minimizing downtime and performance issues leads to a better user experience.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data-Driven Decision Making&lt;/strong&gt;: Real-time insights support informed decision-making.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Integration with Other Observability Tools&lt;/strong&gt;: Seamless integration with other tools enhances overall observability.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Choosing the Right API Monitoring Tool
&lt;/h2&gt;

&lt;p&gt;Selecting the right API monitoring tool is crucial for effective API monitoring. Consider the following factors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Comprehensive Visibility&lt;/strong&gt;: The tool should offer complete visibility into API performance and reliability.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Real-Time Monitoring&lt;/strong&gt;: Ensure the tool provides real-time monitoring and analysis of log data and metrics.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Customizable Alerts&lt;/strong&gt;: Look for tools that offer customizable alerts and notifications for critical issues.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Integration&lt;/strong&gt;: The tool should integrate well with other observability tools and processes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scalability&lt;/strong&gt;: Choose a tool that can scale to meet growing API demands.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Security&lt;/strong&gt;: The tool should implement secure logging practices to protect sensitive data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;User Experience&lt;/strong&gt;: A user-friendly interface is essential for easy monitoring and analysis.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By considering these factors, developers can choose the right API monitoring tool for their needs, ensuring effective API monitoring and observability.&lt;/p&gt;

&lt;h2&gt;
  
  
  1 - Moesif
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.moesif.com/features/api-logs?utm_campaign=Int-site&amp;amp;utm_source=blog&amp;amp;utm_medium=body-cta&amp;amp;utm_content=most-popular-tools-for-logging" rel="noopener noreferrer"&gt;Moesif&lt;/a&gt; is a powerful, feature-rich solution for API monitoring and tracking. Moesif also provides detailed insights into API transactions, capturing information about API requests and responses to ensure quality and performance. Rather than synthetic monitoring, Moesif provides real user monitoring, giving businesses the ability to dive into their API performance and API call data. By combining real-time event logging with product analytics (including API endpoint analysis, API testing, and API gateway integration), monetization systems (including quotas, governance, and metered billing), and alerts (both real-time and behavioral, as well as API security), Moesif promises to unlock better revenue performance, improve user retention, and generate unprecedented insight and awareness across your API.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Provides powerful context and deep introspection through unlocked application-layer visibility&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Easy to set up across a variety of systems and implementations&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Drawbacks
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Governance Rules only available on enterprise tier&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2 - Prometheus
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://prometheus.io/docs/prometheus/latest/management_api/" rel="noopener noreferrer"&gt;Prometheus&lt;/a&gt; is a widely-adopted open source monitoring solution. Prometheus also excels in infrastructure monitoring, helping to ensure system reliability and performance. It has generated quite a following due to its developer outreach backing, with ample documentation, blogs, video content, etc. That being said, Prometheus was designed to generate insights based on metrics, and thus is often considered more an “insights” solution than a “logging” one. Logs are stored locally and are then pointed to by Prometheus when an issue is detected per the metrics – for this reason, users typically use Prometheus in addition to an API logging solution for remote hosting, which makes Prometheus – at least for a subset of users – a half solution for monitoring API products.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Well-documented and easy to implement&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ample insights generated from small amounts of data&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Drawbacks
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Lack of native cloud logging support&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;May not be a complete solve for many users&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3 - Sematext
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://sematext.com/" rel="noopener noreferrer"&gt;Sematext&lt;/a&gt; offers a very popular solution in Sematext Logs. Sematext Logs supports the creation of detailed log entries, capturing essential data for troubleshooting and performance monitoring. Sematext positions their offering as a Log Management-as-a-Service model, supporting the exfiltration of API logs from containers, infrastructure, applications, etc. It facilitates this by supporting Syslog or the Elasticsearch API, which opens it to a wide range of implementations. Because it supports these solutions, you can use Sematext natively, bypassing more expensive options which require third party solutions for performance monitoring.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Wide support for systems and applications&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cheaper to use than many other solutions&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Drawbacks
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Requires using either Syslog or Elasticsearch, which can be limiting in some situations&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Requires buying into the “as-a-Service” dynamic&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4 - Papertrail
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.papertrail.com/" rel="noopener noreferrer"&gt;Papertrail&lt;/a&gt; is a logging solution from SolarWinds Cloud, a Software-as-a-Service solution. Each log entry in Papertrail captures critical elements like timestamps and request details, aiding in diagnosing issues. Papertrail allows for a large amount of customizability, and because it’s part of what is typically a holistic solution, it offers substantial cross-service and cross-database API logging that is often much slower and more expensive in other solutions. The drawback, of course, is that Papertrail works best as part of the SolarWinds Cloud service – and if you’re not using that service, your experience may not be as good as it could be with other open-source or free software solutions. If you currently are a SolarWinds customer, the best solution for your API monitor may be Papertrail.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Highly customizable&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cross-service and cross-database&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Drawbacks
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Part of a suite of offerings that do better as part of SolarWinds Cloud&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Not robustly open-source&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5 - Checkly
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.checklyhq.com/" rel="noopener noreferrer"&gt;Checkly&lt;/a&gt; is a very new player in the logging software scene, but it brings a lot to the table. Checkly provides insights into key metrics such as response times and error rates, crucial for evaluating API performance. Beyond its powerful synthetic monitoring and API logging, it also allows for deep contextual inspection, diving into payload, responses, headers, and more. Latency, which refers to the time delay between API request and response time, is another critical metric Checkly helps to monitor. This amount of logging and API analytics provide a great amount of context and can improve your visibility quite significantly through application performance monitoring. Pricing is relatively simple and follows a freemium model – that being said, more complex environments might quickly run above the relatively modest 10,000 API calls in the free plan, and the custom plan may have higher costs compared to something that is self-hosted.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Relatively inexpensive&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Provides high context&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Drawbacks
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Very new player, so not as proven&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Limited freemium offering&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  6 - Datadog
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.datadoghq.com/" rel="noopener noreferrer"&gt;Datadog&lt;/a&gt; bills itself as an observability platform, offering a relatively feature-complete solution for logging, website monitoring, application monitoring, and reporting for REST API-based products and beyond. Datadog's suite of monitoring tools provides real-time insights into API performance and reliability. It allows users to set specific metric-based rules to generate alerts across channels like Slack, SMS, email, etc. Datadog is relatively cheap, which is a big reason it has seen good adoption across the board – that being said, it doesn’t provide as much detail as some other solutions in the marketplace, making it a good generalist middle-of-the-road API management solution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Feature-complete compared to others on this list&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Relatively cheap to deploy&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Drawbacks
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Limited detail compared to other solutions&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  7 - Sauce Labs
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://saucelabs.com/" rel="noopener noreferrer"&gt;Sauce Labs&lt;/a&gt; used to be called API Fortress, and under that name, it generated a bit of a reputation as a cloud-based REST API monitoring solution. Setting up Sauce Labs for monitoring involves establishing secure connections to ensure data integrity and security. Sauce Labs continues this success by providing testing, monitoring, and reporting, but for those looking principally for API log tooling, Sauce Labs can seem a bit too feature-complete. Ultimately the use case for Sauce Labs is a bit of column A and column B – if you want to collect API logs for the purpose of generating reports and insights, Sauce Labs is a great solution. If you want to log to just log, this might be another in the column of “too good for what you need”.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Very mature in the market&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Widely adopted giving a huge user community&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Drawbacks
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Perhaps too mature for those looking only for logging&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A bit too general for specific use cases&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  8 - Amazon CloudWatch
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://aws.amazon.com/cloudwatch/" rel="noopener noreferrer"&gt;Amazon CloudWatch&lt;/a&gt; brings the proven logging and monitoring approaches on offer from Amazon. Amazon CloudWatch is one of the most flexible API monitoring tools available, offering robust logging and monitoring capabilities. This solution is relatively robust, but the main selling point is in the pricing model – CloudWatch is very flexible, offering pay-as-you-go, which allows for easy scaling. That being said, the solution is tooled specifically for the AWS API gateway, which makes it a hard sell to anyone not utilizing AWS systems. Because of the usage based nature of CloudWatch’s payment structure understanding the performance metric that eat your budget can help guide the decision to use CloudWatch for uptime monitoring or synthetic API monitoring.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Relatively efficient and feature rich&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pay-as-you-go pricing makes it flexible&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Drawbacks
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Tooled for AWS specifically, which may exclude it from some stacks&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  9 - AppDynamics
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.appdynamics.com/" rel="noopener noreferrer"&gt;AppDynamics&lt;/a&gt; is particularly powerful and is backed by the Cisco product offering. It offers real-time data visualization and analysis, and provides relatively robust solutions like resource waterfalls to show the impact of each element of the API service in the overall efficiency and user experience. AppDynamics provides comprehensive monitoring for any application programming interface, ensuring optimal performance and reliability. That being said, this is another offering that is run by a corporate entity, and its quite expensive – for many developers, this might be a huge negative that is difficult to overcome no matter how beautiful the visualizations are in practice.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Backed by Cisco and its mature product offering&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Real-time data visualization&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Drawbacks
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Not open source and corporate in nature&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Quite expensive&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  10 - Uptrends
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.uptrends.com/" rel="noopener noreferrer"&gt;Uptrends&lt;/a&gt; offers a robust multi-step logging and API monitoring tool, selling itself as a logging and alerting system first and foremost. Uptrends offers “Private Checkpoints”, a solution that unlocks testing behind private networks and firewalls. Uptrends is very clearly leaning on its solution as a “problem resolution” one, with one area of the site boasting “Yesterday we detected 332k errors. How's your site doing?”. The main drawback here is that Uptrends is very clearly selling itself as an analysis tool rather than just an API log tool. For developers looking for logging – and just logging – Uptrends is too far down the monitoring path.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Robust logging and monitoring&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Works on private systems and networks&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Drawbacks
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Monitoring-heavy makes logging a second thought&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Provides ample analysis which may just be a cost increase vs. a utility increase for some stacks&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  11 - Graphite
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://graphiteapp.org/" rel="noopener noreferrer"&gt;Graphite&lt;/a&gt; is an open source monitoring and logging system that utilizes a push-based design architecture. What this means is that Graphite allows services to push their API logs into a component called Graphite Carbon, which is then stored in a database for later deep introspection and transformation. Prometheus, another open-source monitoring toolkit designed for cloud-native applications, is often used alongside Graphite for enhanced monitoring capabilities. Graphite's main selling point is its easy deployment through its native Synthesize product, an automated installation and configuration system which promises to get users up and running with minimal headache.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Open source and feature-rich&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Easy deployment&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Drawbacks
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Depends on its own solutions - may be stack limiting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We hope this list has helped you see the offerings in the current marketplace. Please note that this list is not exhaustive – nonetheless, it provides a good overview of the most common solutions available today! Feel free to let us know if there are more solutions you'd love included in this list.&lt;/p&gt;

</description>
      <category>api</category>
      <category>monitoring</category>
      <category>tooling</category>
      <category>developers</category>
    </item>
    <item>
      <title>How we built a Node.js Middleware to Log HTTP API Requests and Responses</title>
      <dc:creator>Moesif Staff</dc:creator>
      <pubDate>Thu, 27 Mar 2025 17:37:21 +0000</pubDate>
      <link>https://dev.to/moesif/how-we-built-a-nodejs-middleware-to-log-http-api-requests-and-responses-bh6</link>
      <guid>https://dev.to/moesif/how-we-built-a-nodejs-middleware-to-log-http-api-requests-and-responses-bh6</guid>
      <description>&lt;p&gt;There are many different runtimes and eco-systems used to build APIs and here at Moesif we try to make integration with them as simple as possible. We build many libraries that help with this integration, one of them is the &lt;a href="https://github.com/Moesif/moesif-nodejs" rel="noopener noreferrer"&gt;Moesif Node.js Middleware Library&lt;/a&gt;, or short moesif-nodejs. Middleware in Node.js is a function that has access to request and response objects and the next middleware function in the request-response cycle.&lt;/p&gt;

&lt;p&gt;Node.js handles requests asynchronously which can sometimes lead to problems, especially when we want to debug our systems or log what they are doing. API logs capture the intricate details of requests and responses exchanged between applications and servers, making them essential for understanding and troubleshooting such asynchronous behavior.&lt;/p&gt;

&lt;p&gt;In this article, we will go through the steps that went into building the moesif-nodejs library, the places where the relevant logging data is and how to hook into Node.js' http module to handle the data-gathering at the right time in the pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction to API Logging
&lt;/h2&gt;

&lt;p&gt;API logging is the process of capturing and recording API interactions, including requests, responses, and errors. API logs provide valuable insights into API performance, security, and usage, enabling developers to troubleshoot issues, optimize performance, and ensure compliance with regulatory standards. In this section, we will explore the importance of API logging, its benefits, and the different types of API logs.&lt;/p&gt;

&lt;p&gt;API logs are essential for monitoring and maintaining the health, security, and efficiency of APIs. They provide a comprehensive view of API interactions, allowing developers to identify trends and patterns in API usage, detect security threats, and optimize performance. API logs can be categorized into different types, including access logs, error logs, security logs, and performance logs.&lt;/p&gt;

&lt;p&gt;Access logs record details about each API request, such as the HTTP method, URL, and response status code. Error logs capture information about any errors that occur during API calls, helping developers identify and fix issues. Security logs track failed authentication attempts and access control violations, providing insights into potential security threats. Performance logs measure the efficiency and response speed of APIs, recording metrics such as response time and throughput.&lt;/p&gt;

&lt;p&gt;By leveraging API logs, developers can gain a deeper understanding of how their APIs are being used, identify and resolve issues more quickly, and ensure that their APIs are secure and performant.&lt;/p&gt;

&lt;p&gt;For developers looking for an effortless way to monitor and analyze API traffic, integrating Moesif can significantly streamline this process. Moesif’s API analytics platform provides deep insights into API usage, identifying trends and performance bottlenecks while ensuring compliance with security policies. By leveraging tools like the Moesif Node.js Middleware, developers can log API requests and responses efficiently without modifying their core application logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Middleware in Node.js
&lt;/h2&gt;

&lt;p&gt;In Node.js, middleware is a function that can access the request object (req), the Middleware functions can perform tasks such as authentication, caching, and compression, and can be used to handle HTTP requests and responses. In this section, we will explore the concept of middleware in Node.js, its benefits, and how to create and use middleware functions.&lt;/p&gt;

&lt;p&gt;Middleware functions are essential in Node.js applications, as they enable developers to perform tasks that are common to multiple routes or endpoints. Middleware functions can be used to authenticate users, cache frequently accessed data, and compress responses to improve performance. Node.js provides several built-in middleware functions, including express.static, express.json, and express.urlencoded.&lt;/p&gt;

&lt;p&gt;The express.static middleware function serves static files, such as images, CSS files, and JavaScript files, from a specified directory. The express.json middleware function parses incoming requests with JSON payloads, making it easier to work with JSON data. The express.urlencoded middleware function parses incoming requests with URL-encoded payloads, which is useful for handling form submissions.&lt;/p&gt;

&lt;p&gt;By using middleware functions, developers can create modular and maintainable code, as each middleware function can be responsible for a specific task. This modularity makes it easier to manage and update the application, as changes to one middleware function do not affect others.&lt;/p&gt;

&lt;p&gt;For instance, Moesif’s middleware for Node.js seamlessly integrates into Express applications, allowing developers to capture request-response data for logging, debugging, and analytics. This approach not only simplifies tracking API performance but also enables real-time monitoring, anomaly detection, and automated alerts—essential for ensuring API reliability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Node.js' HTTP Module
&lt;/h2&gt;

&lt;p&gt;Node.js comes with an HTTP-server implementation out-of-the-box, while it isn’t used directly in most applications, it’s a good start to understand the basics of requests and responses.&lt;/p&gt;

&lt;p&gt;In a middleware setup, the current middleware function plays a crucial role in managing the request-response cycle. If the current middleware function does not complete the cycle, it must invoke the next middleware function to prevent requests from being left hanging.&lt;/p&gt;

&lt;h2&gt;
  
  
  Designing the Middleware Function
&lt;/h2&gt;

&lt;p&gt;Designing a middleware function involves several steps, including defining the function signature, accessing the request and response objects, and calling the next middleware function. In this section, we will explore the best practices for designing middleware functions, including how to handle errors, how to access and modify the request and response objects, and how to call the next middleware function.&lt;/p&gt;

&lt;p&gt;When designing a middleware function, it is essential to consider the function signature, which includes the request object (req), the response object (res), and the next middleware function (next). The middleware function should access and modify the request and response objects as needed, and call the next middleware function to pass control to the next function in the chain.&lt;/p&gt;

&lt;p&gt;To handle errors effectively, the middleware function should include error-handling logic. This can be done by checking for errors in the request and response objects and logging any errors that occur. Additionally, the middleware function should call the next middleware function with an error argument if an error is detected, allowing the error to be handled by error-handling middleware functions.&lt;/p&gt;

&lt;p&gt;Accessing and modifying the request and response objects is a common task in middleware functions. For example, a middleware function might add a custom header to the response object or modify the request object to include additional data. It is important to ensure that any modifications to the request and response objects do not interfere with other middleware functions or the final response.&lt;/p&gt;

&lt;p&gt;Calling the next middleware function is crucial for ensuring that the request-response cycle continues. The middleware function should call the next middleware function after completing its task, passing control to the next function in the chain. This allows multiple middleware functions to work together to handle a single request.&lt;/p&gt;

&lt;p&gt;By following these best practices, developers can design effective and efficient middleware functions that enhance the functionality and maintainability of their Node.js applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic Logging of a GET Request
&lt;/h2&gt;

&lt;p&gt;The idea behind logging is that we write some kind of data in some persistent data store so we can review it later. To keep things simple, we will first write to stdout with console.log() Sometimes logging to stdout isn’t an option and we have to send the logging data to some other place. Like when running in a serverless environment, where the functions have no persistent storage. Let’s try a simple server that does nothing but sending empty responses for every request to illustrate how to get request data that can be logged. const http = require("http");&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;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="s2"&gt;http&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;server&lt;/span&gt; &lt;span class="o"&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;createServer&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="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;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;server&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="mi"&gt;8888&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we send a request to &lt;a href="http://localhost:8888/" rel="noopener noreferrer"&gt;http://localhost:8888&lt;/a&gt; we see a giant object being logged to stdout, it is full of implementation details and finding the important parts isn’t easy. These log details include various components such as timestamps, client information, request and response details, and security events, which are essential for troubleshooting issues, monitoring performance, and recognizing potential security threats.&lt;/p&gt;

&lt;p&gt;Let’s look at the Node.js documentation for &lt;a href="https://nodejs.org/dist/latest-v10.x/docs/api/http.html#http_class_http_incomingmessage" rel="noopener noreferrer"&gt;IncomingMessage&lt;/a&gt;, the class of which our requests is an object of.&lt;/p&gt;

&lt;p&gt;What information can we find here?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;headers&lt;/code&gt; and &lt;code&gt;rawHeaders&lt;/code&gt; (for invalid/duplicate headers)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;httpVersion&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;method&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;url&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;socket.remoteAddress&lt;/code&gt; (for the client IP)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This should be enough for GET requests since they usually don't have a body. Let's update our implementation.&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;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&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;createServer&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rawHeaders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;httpVersion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&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="nx"&gt;remoteAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;remoteFamily&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;socket&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;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="nx"&gt;rawHeaders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;httpVersion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;remoteAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;remoteFamily&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;url&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&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;The output should look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1562331336922&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rawHeaders"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"cache-control"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"no-cache"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Postman-Token"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"dcd81e98-4f98-42a3-9e13-10c8401892b3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"User-Agent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"PostmanRuntime/7.6.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Accept"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"*/*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Host"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"localhost:8888"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"accept-encoding"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"gzip, deflate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Connection"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"keep alive"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"httpVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"remoteAddress"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"::1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"remoteFamily"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"IPv6"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We only use specific parts of the request for our logging. It uses JSON as format so it’s a structured logging approach and has a timestamp so know we not only know what was requested by whom but also when the request started. Structured logging uses a uniform format across all log entries to facilitate easier querying and analysis.&lt;/p&gt;

&lt;h2&gt;
  
  
  Logging Processing Time
&lt;/h2&gt;

&lt;p&gt;If we wanted to add data about how long the request took to process, we need a way to check when it's finished. Performance logs measure the efficiency and response speed of APIs, recording metrics such as response time and throughput, which can be useful for such analysis.&lt;/p&gt;

&lt;p&gt;The request is done when we finished sending our response, so we have to check when a response.end() was called. In our example, this is rather simple, but sometimes these end-calls are done by other modules.&lt;/p&gt;

&lt;p&gt;For this, we can look at the docs of the &lt;a href="https://nodejs.org/dist/latest-v10.x/docs/api/http.html#http_class_http_serverresponse" rel="noopener noreferrer"&gt;ServerResponse&lt;/a&gt; class. It mentions a finish event that is fired when all the sever finished sending it's response. This doesn't mean the client received everything, but it's an indicator that our work is done.&lt;/p&gt;

&lt;p&gt;Let's update our code!&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;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&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;createServer&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="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;requestStart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="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="s2"&gt;finish&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rawHeaders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;httpVersion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&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="nx"&gt;remoteAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;remoteFamily&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;socket&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;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="na"&gt;processingTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;requestStart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;rawHeaders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;httpVersion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;remoteAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;remoteFamily&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;url&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We passed the processing of our request to a separate function to simulate an &lt;em&gt;other module&lt;/em&gt; that takes care of it. The processing takes place asynchronously, because of the &lt;code&gt;setTimeout&lt;/code&gt;, so synchronous logging wouldn't get the desired result, but the &lt;code&gt;finish&lt;/code&gt; event takes care of this by firing &lt;em&gt;after&lt;/em&gt; &lt;code&gt;response.end()&lt;/code&gt; was called.&lt;/p&gt;

&lt;h2&gt;
  
  
  Logging the Body
&lt;/h2&gt;

&lt;p&gt;The request body is still not logged, which means POST, PUT and PATCH requests aren't 100% covered.&lt;/p&gt;

&lt;p&gt;To get the body into the logs too, we need a way to extract it from our request object.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://nodejs.org/dist/latest-v10.x/docs/api/http.html#http_class_http_incomingmessage" rel="noopener noreferrer"&gt;IncomingMessage&lt;/a&gt; class implements the &lt;a href="https://nodejs.org/dist/latest-v10.x/docs/api/stream.html#stream_class_stream_readable" rel="noopener noreferrer"&gt;ReadableStream&lt;/a&gt; interface. It uses the events of that interface to signal when body data from the client arrives.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;data&lt;/code&gt; event is fired when the server received new chunks of data from the client&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;end&lt;/code&gt; event is called when all data has been sent&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;error&lt;/code&gt; event is called when something goes wrong&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's update our code:&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;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&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;createServer&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="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;requestStart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&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;errorMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&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;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nx"&gt;request&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="s2"&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;chunk&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;body&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;chunk&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;request&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="s2"&gt;end&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&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;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;request&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="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="nx"&gt;error&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;errorMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&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="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="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="s2"&gt;finish&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rawHeaders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;httpVersion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&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="nx"&gt;remoteAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;remoteFamily&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;socket&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;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="na"&gt;processingTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;requestStart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;rawHeaders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;errorMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;httpVersion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;remoteAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;remoteFamily&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;url&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way we log an additional error message when something goes wrong and add the body content to the logging.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Caution: The body can be very big and/or binary, so validation checks are needed, otherwise the amount of data or the encoding can mess up our logs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Logging Response Data
&lt;/h2&gt;

&lt;p&gt;Now that we got the requests down, the next step is the logging of our responses.&lt;/p&gt;

&lt;p&gt;We already listen to the &lt;code&gt;finish&lt;/code&gt; event of our response, so we have a pretty safe way to get all the data. We just have to extract what the response object holds.&lt;/p&gt;

&lt;p&gt;Let's look at the docs for the &lt;a href="https://nodejs.org/dist/latest-v10.x/docs/api/http.html#http_class_http_serverresponse" rel="noopener noreferrer"&gt;ServerResponse&lt;/a&gt; class to find out what it offers us.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;statusCode&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;statusMessage&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;getHeaders()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's add it to our code.&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;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&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;createServer&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="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;requestStart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&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;errorMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&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;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nx"&gt;request&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="s2"&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;chunk&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;body&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;chunk&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;request&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="s2"&gt;end&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&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;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;request&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="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="nx"&gt;error&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;errorMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&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="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="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="s2"&gt;finish&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rawHeaders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;httpVersion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&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="nx"&gt;remoteAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;remoteFamily&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;socket&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="nx"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;statusMessage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&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;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getHeaders&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;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="na"&gt;processingTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;requestStart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;rawHeaders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;errorMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;httpVersion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;remoteAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;remoteFamily&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;statusMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;headers&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Handling Response Errors and Client Aborts
&lt;/h2&gt;

&lt;p&gt;At the moment we only log when the response &lt;code&gt;finish&lt;/code&gt; event is fired, this isn't the case if something goes wrong in response or if the client aborts the request.&lt;/p&gt;

&lt;p&gt;For these two cases, we need to create additional handlers.&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;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&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;createServer&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="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;requestStart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&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;body&lt;/span&gt; &lt;span class="o"&gt;=&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;requestErrorMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&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;getChunk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;assembleBody&lt;/span&gt; &lt;span class="o"&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;body&lt;/span&gt; &lt;span class="o"&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;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&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;getError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&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;requestErrorMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&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="p"&gt;};&lt;/span&gt;
  &lt;span class="nx"&gt;request&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="s2"&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;getChunk&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;request&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="s2"&gt;end&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;assembleBody&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;request&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="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="nx"&gt;getError&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;logClose&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;removeHandlers&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;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Client aborted.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;logError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;removeHandlers&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;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&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="p"&gt;};&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;logFinish&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;removeHandlers&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;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requestErrorMessage&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="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="s2"&gt;close&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;logClose&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="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="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="nx"&gt;logError&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="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="s2"&gt;finish&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;logFinish&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;removeHandlers&lt;/span&gt; &lt;span class="o"&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;request&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="s2"&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;getChunk&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;request&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="s2"&gt;end&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;assembleBody&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;request&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="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="nx"&gt;getError&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="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="s2"&gt;close&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;logClose&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="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="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="nx"&gt;logError&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="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="s2"&gt;finish&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;logFinish&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;errorMessage&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rawHeaders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;httpVersion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&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="nx"&gt;remoteAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;remoteFamily&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;socket&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="nx"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;statusMessage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&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;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getHeaders&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;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="na"&gt;processingTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;requestStart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;rawHeaders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;errorMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;httpVersion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;remoteAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;remoteFamily&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;statusMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;headers&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we also log errors and aborts.&lt;/p&gt;

&lt;p&gt;The logging handlers are also removed when the response finished and all the logging is moved to an extra function.&lt;/p&gt;

&lt;h2&gt;
  
  
  Logging to an external API
&lt;/h2&gt;

&lt;p&gt;At the moment the script only writes its logs to the console and in many cases, this is enough because operating systems allow other programs to capture the stdout and do their thing with it, like writing into a file or sending it to a third-party API like Moesif, for example. API logs are vital tools for monitoring the health of APIs, optimizing performance, and ensuring compliance with regulatory standards.&lt;/p&gt;

&lt;p&gt;In some environments, this isn't possible, but since we gathered all information into one place, we can replace the call to console.log with a third-party function.&lt;/p&gt;

&lt;p&gt;Let's refactor the code so it resembles a library and logs to some external service.&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;const&lt;/span&gt; &lt;span class="nx"&gt;log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;loggingLibrary&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;XYZ&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;server&lt;/span&gt; &lt;span class="o"&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;createServer&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&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;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;loggingLibray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;config&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;loggingApiHeaders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bearer &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apiKey&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;errorMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requestStart&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rawHeaders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;httpVersion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&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="nx"&gt;remoteAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;remoteFamily&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;socket&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="nx"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;statusMessage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&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;responseHeaders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getHeaders&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;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://example.org/logging-endpoint&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;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;loggingApiHeaders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;requestStart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;processingTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;requestStart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;rawHeaders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;errorMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;httpVersion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;remoteAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;remoteFamily&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;statusMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;responseHeaders&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="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;requestStart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// ========== REQUEST HANLDING ==========&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&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;requestErrorMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&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;getChunk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;assembleBody&lt;/span&gt; &lt;span class="o"&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;body&lt;/span&gt; &lt;span class="o"&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;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&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;getError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&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;requestErrorMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&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="p"&gt;};&lt;/span&gt;
    &lt;span class="nx"&gt;request&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="s2"&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;getChunk&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;request&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="s2"&gt;end&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;assembleBody&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;request&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="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="nx"&gt;getError&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// ========== RESPONSE HANLDING ==========&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;logClose&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;removeHandlers&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;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Client aborted.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requestStart&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;logError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;removeHandlers&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;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&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="nx"&gt;requestStart&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;logFinish&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;removeHandlers&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;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requestErrorMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requestStart&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="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="s2"&gt;close&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;logClose&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="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="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="nx"&gt;logError&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="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="s2"&gt;finish&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;logFinish&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// ========== CLEANUP ==========&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;removeHandlers&lt;/span&gt; &lt;span class="o"&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;request&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="s2"&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;getChunk&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;request&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="s2"&gt;end&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;assembleBody&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;request&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="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="nx"&gt;getError&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="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="s2"&gt;close&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;logClose&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="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="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="nx"&gt;logError&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="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="s2"&gt;finish&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;logFinish&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With these changes, we can now use our logging implementation as we would use &lt;a href="https://github.com/Moesif/moesif-nodejs" rel="noopener noreferrer"&gt;moesif-nodejs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;loggingLibrary&lt;/code&gt; function takes an API-key as configuration and returns the actual logging-function that will send the log-data to a logging service via HTTP. The logging-function itself takes a &lt;code&gt;request&lt;/code&gt; and &lt;code&gt;response&lt;/code&gt; object.&lt;/p&gt;

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

&lt;p&gt;With these changes, we can now use our logging implementation as we would use &lt;a href="https://github.com/Moesif/moesif-nodejs" rel="noopener noreferrer"&gt;moesif-nodejs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The loggingLibrary function takes an API-key as configuration and returns the actual logging-function that will send the log-data to a logging service via HTTP. The logging-function itself takes a requestresponse object.&lt;/p&gt;

&lt;p&gt;Here are a few:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/trentm/node-bunyan" rel="noopener noreferrer"&gt;Bunyan&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/visionmedia/debug" rel="noopener noreferrer"&gt;Debug&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/log4js-node/log4js-node" rel="noopener noreferrer"&gt;Log4js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/expressjs/morgan" rel="noopener noreferrer"&gt;Morgan&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/npm/npmlog" rel="noopener noreferrer"&gt;Npmlog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/winstonjs/winston" rel="noopener noreferrer"&gt;Winston&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For developers who want deeper visibility into API traffic with minimal setup, &lt;a href="https://www.moesif.com/wrap?onboard=true&amp;amp;utm_source=devto&amp;amp;utm_medium=bottom-cta&amp;amp;utm_content=how-we-built-nodejs-middleware" rel="noopener noreferrer"&gt;Moesif&lt;/a&gt; offers a seamless solution. Unlike traditional logging libraries, Moesif provides real-time API analytics, retention tracking, and security monitoring, making it an essential tool for scaling and optimizing API-driven applications.&lt;/p&gt;

</description>
      <category>node</category>
      <category>middleware</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How we built a Node.js Middleware to Log HTTP API Requests and Responses</title>
      <dc:creator>Moesif Staff</dc:creator>
      <pubDate>Thu, 27 Mar 2025 17:37:21 +0000</pubDate>
      <link>https://dev.to/moesif/how-we-built-a-nodejs-middleware-to-log-http-api-requests-and-responses-356f</link>
      <guid>https://dev.to/moesif/how-we-built-a-nodejs-middleware-to-log-http-api-requests-and-responses-356f</guid>
      <description>&lt;p&gt;There are many different runtimes and eco-systems used to build APIs and here at Moesif we try to make integration with them as simple as possible. We build many libraries that help with this integration, one of them is the &lt;a href="https://github.com/Moesif/moesif-nodejs" rel="noopener noreferrer"&gt;Moesif Node.js Middleware Library&lt;/a&gt;, or short moesif-nodejs. Middleware in Node.js is a function that has access to request and response objects and the next middleware function in the request-response cycle.&lt;/p&gt;

&lt;p&gt;Node.js handles requests asynchronously which can sometimes lead to problems, especially when we want to debug our systems or log what they are doing. API logs capture the intricate details of requests and responses exchanged between applications and servers, making them essential for understanding and troubleshooting such asynchronous behavior.&lt;/p&gt;

&lt;p&gt;In this article, we will go through the steps that went into building the moesif-nodejs library, the places where the relevant logging data is and how to hook into Node.js' http module to handle the data-gathering at the right time in the pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction to API Logging
&lt;/h2&gt;

&lt;p&gt;API logging is the process of capturing and recording API interactions, including requests, responses, and errors. API logs provide valuable insights into API performance, security, and usage, enabling developers to troubleshoot issues, optimize performance, and ensure compliance with regulatory standards. In this section, we will explore the importance of API logging, its benefits, and the different types of API logs.&lt;/p&gt;

&lt;p&gt;API logs are essential for monitoring and maintaining the health, security, and efficiency of APIs. They provide a comprehensive view of API interactions, allowing developers to identify trends and patterns in API usage, detect security threats, and optimize performance. API logs can be categorized into different types, including access logs, error logs, security logs, and performance logs.&lt;/p&gt;

&lt;p&gt;Access logs record details about each API request, such as the HTTP method, URL, and response status code. Error logs capture information about any errors that occur during API calls, helping developers identify and fix issues. Security logs track failed authentication attempts and access control violations, providing insights into potential security threats. Performance logs measure the efficiency and response speed of APIs, recording metrics such as response time and throughput.&lt;/p&gt;

&lt;p&gt;By leveraging API logs, developers can gain a deeper understanding of how their APIs are being used, identify and resolve issues more quickly, and ensure that their APIs are secure and performant.&lt;/p&gt;

&lt;p&gt;For developers looking for an effortless way to monitor and analyze API traffic, integrating Moesif can significantly streamline this process. Moesif’s API analytics platform provides deep insights into API usage, identifying trends and performance bottlenecks while ensuring compliance with security policies. By leveraging tools like the Moesif Node.js Middleware, developers can log API requests and responses efficiently without modifying their core application logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Middleware in Node.js
&lt;/h2&gt;

&lt;p&gt;In Node.js, middleware is a function that can access the request object (req), the Middleware functions can perform tasks such as authentication, caching, and compression, and can be used to handle HTTP requests and responses. In this section, we will explore the concept of middleware in Node.js, its benefits, and how to create and use middleware functions.&lt;/p&gt;

&lt;p&gt;Middleware functions are essential in Node.js applications, as they enable developers to perform tasks that are common to multiple routes or endpoints. Middleware functions can be used to authenticate users, cache frequently accessed data, and compress responses to improve performance. Node.js provides several built-in middleware functions, including express.static, express.json, and express.urlencoded.&lt;/p&gt;

&lt;p&gt;The express.static middleware function serves static files, such as images, CSS files, and JavaScript files, from a specified directory. The express.json middleware function parses incoming requests with JSON payloads, making it easier to work with JSON data. The express.urlencoded middleware function parses incoming requests with URL-encoded payloads, which is useful for handling form submissions.&lt;/p&gt;

&lt;p&gt;By using middleware functions, developers can create modular and maintainable code, as each middleware function can be responsible for a specific task. This modularity makes it easier to manage and update the application, as changes to one middleware function do not affect others.&lt;/p&gt;

&lt;p&gt;For instance, Moesif’s middleware for Node.js seamlessly integrates into Express applications, allowing developers to capture request-response data for logging, debugging, and analytics. This approach not only simplifies tracking API performance but also enables real-time monitoring, anomaly detection, and automated alerts—essential for ensuring API reliability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Node.js' HTTP Module
&lt;/h2&gt;

&lt;p&gt;Node.js comes with an HTTP-server implementation out-of-the-box, while it isn’t used directly in most applications, it’s a good start to understand the basics of requests and responses.&lt;/p&gt;

&lt;p&gt;In a middleware setup, the current middleware function plays a crucial role in managing the request-response cycle. If the current middleware function does not complete the cycle, it must invoke the next middleware function to prevent requests from being left hanging.&lt;/p&gt;

&lt;h2&gt;
  
  
  Designing the Middleware Function
&lt;/h2&gt;

&lt;p&gt;Designing a middleware function involves several steps, including defining the function signature, accessing the request and response objects, and calling the next middleware function. In this section, we will explore the best practices for designing middleware functions, including how to handle errors, how to access and modify the request and response objects, and how to call the next middleware function.&lt;/p&gt;

&lt;p&gt;When designing a middleware function, it is essential to consider the function signature, which includes the request object (req), the response object (res), and the next middleware function (next). The middleware function should access and modify the request and response objects as needed, and call the next middleware function to pass control to the next function in the chain.&lt;/p&gt;

&lt;p&gt;To handle errors effectively, the middleware function should include error-handling logic. This can be done by checking for errors in the request and response objects and logging any errors that occur. Additionally, the middleware function should call the next middleware function with an error argument if an error is detected, allowing the error to be handled by error-handling middleware functions.&lt;/p&gt;

&lt;p&gt;Accessing and modifying the request and response objects is a common task in middleware functions. For example, a middleware function might add a custom header to the response object or modify the request object to include additional data. It is important to ensure that any modifications to the request and response objects do not interfere with other middleware functions or the final response.&lt;/p&gt;

&lt;p&gt;Calling the next middleware function is crucial for ensuring that the request-response cycle continues. The middleware function should call the next middleware function after completing its task, passing control to the next function in the chain. This allows multiple middleware functions to work together to handle a single request.&lt;/p&gt;

&lt;p&gt;By following these best practices, developers can design effective and efficient middleware functions that enhance the functionality and maintainability of their Node.js applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic Logging of a GET Request
&lt;/h2&gt;

&lt;p&gt;The idea behind logging is that we write some kind of data in some persistent data store so we can review it later. To keep things simple, we will first write to stdout with console.log() Sometimes logging to stdout isn’t an option and we have to send the logging data to some other place. Like when running in a serverless environment, where the functions have no persistent storage. Let’s try a simple server that does nothing but sending empty responses for every request to illustrate how to get request data that can be logged. const http = require("http");&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;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="s2"&gt;http&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;server&lt;/span&gt; &lt;span class="o"&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;createServer&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="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;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;server&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="mi"&gt;8888&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we send a request to &lt;a href="http://localhost:8888/" rel="noopener noreferrer"&gt;http://localhost:8888&lt;/a&gt; we see a giant object being logged to stdout, it is full of implementation details and finding the important parts isn’t easy. These log details include various components such as timestamps, client information, request and response details, and security events, which are essential for troubleshooting issues, monitoring performance, and recognizing potential security threats.&lt;/p&gt;

&lt;p&gt;Let’s look at the Node.js documentation for &lt;a href="https://nodejs.org/dist/latest-v10.x/docs/api/http.html#http_class_http_incomingmessage" rel="noopener noreferrer"&gt;IncomingMessage&lt;/a&gt;, the class of which our requests is an object of.&lt;/p&gt;

&lt;p&gt;What information can we find here?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;headers&lt;/code&gt; and &lt;code&gt;rawHeaders&lt;/code&gt; (for invalid/duplicate headers)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;httpVersion&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;method&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;url&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;socket.remoteAddress&lt;/code&gt; (for the client IP)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This should be enough for GET requests since they usually don't have a body. Let's update our implementation.&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;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&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;createServer&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rawHeaders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;httpVersion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&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="nx"&gt;remoteAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;remoteFamily&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;socket&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;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="nx"&gt;rawHeaders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;httpVersion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;remoteAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;remoteFamily&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;url&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&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;The output should look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1562331336922&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rawHeaders"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"cache-control"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"no-cache"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Postman-Token"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"dcd81e98-4f98-42a3-9e13-10c8401892b3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"User-Agent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"PostmanRuntime/7.6.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Accept"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"*/*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Host"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"localhost:8888"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"accept-encoding"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"gzip, deflate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Connection"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"keep alive"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"httpVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"remoteAddress"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"::1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"remoteFamily"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"IPv6"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We only use specific parts of the request for our logging. It uses JSON as format so it’s a structured logging approach and has a timestamp so know we not only know what was requested by whom but also when the request started. Structured logging uses a uniform format across all log entries to facilitate easier querying and analysis.&lt;/p&gt;

&lt;h2&gt;
  
  
  Logging Processing Time
&lt;/h2&gt;

&lt;p&gt;If we wanted to add data about how long the request took to process, we need a way to check when it's finished. Performance logs measure the efficiency and response speed of APIs, recording metrics such as response time and throughput, which can be useful for such analysis.&lt;/p&gt;

&lt;p&gt;The request is done when we finished sending our response, so we have to check when a response.end() was called. In our example, this is rather simple, but sometimes these end-calls are done by other modules.&lt;/p&gt;

&lt;p&gt;For this, we can look at the docs of the &lt;a href="https://nodejs.org/dist/latest-v10.x/docs/api/http.html#http_class_http_serverresponse" rel="noopener noreferrer"&gt;ServerResponse&lt;/a&gt; class. It mentions a finish event that is fired when all the sever finished sending it's response. This doesn't mean the client received everything, but it's an indicator that our work is done.&lt;/p&gt;

&lt;p&gt;Let's update our code!&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;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&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;createServer&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="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;requestStart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="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="s2"&gt;finish&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rawHeaders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;httpVersion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&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="nx"&gt;remoteAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;remoteFamily&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;socket&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;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="na"&gt;processingTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;requestStart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;rawHeaders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;httpVersion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;remoteAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;remoteFamily&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;url&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We passed the processing of our request to a separate function to simulate an &lt;em&gt;other module&lt;/em&gt; that takes care of it. The processing takes place asynchronously, because of the &lt;code&gt;setTimeout&lt;/code&gt;, so synchronous logging wouldn't get the desired result, but the &lt;code&gt;finish&lt;/code&gt; event takes care of this by firing &lt;em&gt;after&lt;/em&gt; &lt;code&gt;response.end()&lt;/code&gt; was called.&lt;/p&gt;

&lt;h2&gt;
  
  
  Logging the Body
&lt;/h2&gt;

&lt;p&gt;The request body is still not logged, which means POST, PUT and PATCH requests aren't 100% covered.&lt;/p&gt;

&lt;p&gt;To get the body into the logs too, we need a way to extract it from our request object.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://nodejs.org/dist/latest-v10.x/docs/api/http.html#http_class_http_incomingmessage" rel="noopener noreferrer"&gt;IncomingMessage&lt;/a&gt; class implements the &lt;a href="https://nodejs.org/dist/latest-v10.x/docs/api/stream.html#stream_class_stream_readable" rel="noopener noreferrer"&gt;ReadableStream&lt;/a&gt; interface. It uses the events of that interface to signal when body data from the client arrives.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;data&lt;/code&gt; event is fired when the server received new chunks of data from the client&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;end&lt;/code&gt; event is called when all data has been sent&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;error&lt;/code&gt; event is called when something goes wrong&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's update our code:&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;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&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;createServer&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="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;requestStart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&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;errorMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&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;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nx"&gt;request&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="s2"&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;chunk&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;body&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;chunk&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;request&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="s2"&gt;end&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&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;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;request&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="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="nx"&gt;error&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;errorMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&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="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="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="s2"&gt;finish&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rawHeaders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;httpVersion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&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="nx"&gt;remoteAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;remoteFamily&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;socket&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;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="na"&gt;processingTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;requestStart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;rawHeaders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;errorMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;httpVersion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;remoteAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;remoteFamily&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;url&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way we log an additional error message when something goes wrong and add the body content to the logging.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Caution: The body can be very big and/or binary, so validation checks are needed, otherwise the amount of data or the encoding can mess up our logs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Logging Response Data
&lt;/h2&gt;

&lt;p&gt;Now that we got the requests down, the next step is the logging of our responses.&lt;/p&gt;

&lt;p&gt;We already listen to the &lt;code&gt;finish&lt;/code&gt; event of our response, so we have a pretty safe way to get all the data. We just have to extract what the response object holds.&lt;/p&gt;

&lt;p&gt;Let's look at the docs for the &lt;a href="https://nodejs.org/dist/latest-v10.x/docs/api/http.html#http_class_http_serverresponse" rel="noopener noreferrer"&gt;ServerResponse&lt;/a&gt; class to find out what it offers us.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;statusCode&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;statusMessage&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;getHeaders()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's add it to our code.&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;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&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;createServer&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="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;requestStart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&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;errorMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&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;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nx"&gt;request&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="s2"&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;chunk&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;body&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;chunk&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;request&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="s2"&gt;end&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&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;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;request&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="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="nx"&gt;error&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;errorMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&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="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="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="s2"&gt;finish&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rawHeaders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;httpVersion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&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="nx"&gt;remoteAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;remoteFamily&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;socket&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="nx"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;statusMessage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&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;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getHeaders&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;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="na"&gt;processingTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;requestStart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;rawHeaders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;errorMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;httpVersion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;remoteAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;remoteFamily&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;statusMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;headers&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Handling Response Errors and Client Aborts
&lt;/h2&gt;

&lt;p&gt;At the moment we only log when the response &lt;code&gt;finish&lt;/code&gt; event is fired, this isn't the case if something goes wrong in response or if the client aborts the request.&lt;/p&gt;

&lt;p&gt;For these two cases, we need to create additional handlers.&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;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&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;createServer&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="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;requestStart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&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;body&lt;/span&gt; &lt;span class="o"&gt;=&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;requestErrorMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&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;getChunk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;assembleBody&lt;/span&gt; &lt;span class="o"&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;body&lt;/span&gt; &lt;span class="o"&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;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&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;getError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&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;requestErrorMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&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="p"&gt;};&lt;/span&gt;
  &lt;span class="nx"&gt;request&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="s2"&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;getChunk&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;request&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="s2"&gt;end&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;assembleBody&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;request&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="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="nx"&gt;getError&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;logClose&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;removeHandlers&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;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Client aborted.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;logError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;removeHandlers&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;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&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="p"&gt;};&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;logFinish&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;removeHandlers&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;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requestErrorMessage&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="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="s2"&gt;close&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;logClose&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="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="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="nx"&gt;logError&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="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="s2"&gt;finish&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;logFinish&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;removeHandlers&lt;/span&gt; &lt;span class="o"&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;request&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="s2"&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;getChunk&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;request&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="s2"&gt;end&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;assembleBody&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;request&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="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="nx"&gt;getError&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="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="s2"&gt;close&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;logClose&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="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="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="nx"&gt;logError&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="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="s2"&gt;finish&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;logFinish&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;errorMessage&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rawHeaders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;httpVersion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&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="nx"&gt;remoteAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;remoteFamily&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;socket&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="nx"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;statusMessage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&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;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getHeaders&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;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="na"&gt;processingTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;requestStart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;rawHeaders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;errorMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;httpVersion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;remoteAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;remoteFamily&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;statusMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;headers&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we also log errors and aborts.&lt;/p&gt;

&lt;p&gt;The logging handlers are also removed when the response finished and all the logging is moved to an extra function.&lt;/p&gt;

&lt;h2&gt;
  
  
  Logging to an external API
&lt;/h2&gt;

&lt;p&gt;At the moment the script only writes its logs to the console and in many cases, this is enough because operating systems allow other programs to capture the stdout and do their thing with it, like writing into a file or sending it to a third-party API like Moesif, for example. API logs are vital tools for monitoring the health of APIs, optimizing performance, and ensuring compliance with regulatory standards.&lt;/p&gt;

&lt;p&gt;In some environments, this isn't possible, but since we gathered all information into one place, we can replace the call to console.log with a third-party function.&lt;/p&gt;

&lt;p&gt;Let's refactor the code so it resembles a library and logs to some external service.&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;const&lt;/span&gt; &lt;span class="nx"&gt;log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;loggingLibrary&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;XYZ&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;server&lt;/span&gt; &lt;span class="o"&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;createServer&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&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;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;loggingLibray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;config&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;loggingApiHeaders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bearer &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apiKey&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;errorMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requestStart&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rawHeaders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;httpVersion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&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="nx"&gt;remoteAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;remoteFamily&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;socket&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="nx"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;statusMessage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&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;responseHeaders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getHeaders&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;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://example.org/logging-endpoint&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;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;loggingApiHeaders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;requestStart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;processingTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;requestStart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;rawHeaders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;errorMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;httpVersion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;remoteAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;remoteFamily&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;statusMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;responseHeaders&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="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;requestStart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// ========== REQUEST HANLDING ==========&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&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;requestErrorMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&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;getChunk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;assembleBody&lt;/span&gt; &lt;span class="o"&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;body&lt;/span&gt; &lt;span class="o"&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;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&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;getError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&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;requestErrorMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&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="p"&gt;};&lt;/span&gt;
    &lt;span class="nx"&gt;request&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="s2"&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;getChunk&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;request&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="s2"&gt;end&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;assembleBody&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;request&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="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="nx"&gt;getError&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// ========== RESPONSE HANLDING ==========&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;logClose&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;removeHandlers&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;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Client aborted.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requestStart&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;logError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;removeHandlers&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;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&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="nx"&gt;requestStart&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;logFinish&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;removeHandlers&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;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requestErrorMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requestStart&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="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="s2"&gt;close&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;logClose&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="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="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="nx"&gt;logError&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="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="s2"&gt;finish&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;logFinish&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// ========== CLEANUP ==========&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;removeHandlers&lt;/span&gt; &lt;span class="o"&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;request&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="s2"&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;getChunk&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;request&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="s2"&gt;end&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;assembleBody&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;request&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="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="nx"&gt;getError&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="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="s2"&gt;close&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;logClose&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="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="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="nx"&gt;logError&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="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="s2"&gt;finish&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;logFinish&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With these changes, we can now use our logging implementation as we would use &lt;a href="https://github.com/Moesif/moesif-nodejs" rel="noopener noreferrer"&gt;moesif-nodejs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;loggingLibrary&lt;/code&gt; function takes an API-key as configuration and returns the actual logging-function that will send the log-data to a logging service via HTTP. The logging-function itself takes a &lt;code&gt;request&lt;/code&gt; and &lt;code&gt;response&lt;/code&gt; object.&lt;/p&gt;

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

&lt;p&gt;With these changes, we can now use our logging implementation as we would use &lt;a href="https://github.com/Moesif/moesif-nodejs" rel="noopener noreferrer"&gt;moesif-nodejs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The loggingLibrary function takes an API-key as configuration and returns the actual logging-function that will send the log-data to a logging service via HTTP. The logging-function itself takes a requestresponse object.&lt;/p&gt;

&lt;p&gt;Here are a few:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/trentm/node-bunyan" rel="noopener noreferrer"&gt;Bunyan&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/visionmedia/debug" rel="noopener noreferrer"&gt;Debug&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/log4js-node/log4js-node" rel="noopener noreferrer"&gt;Log4js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/expressjs/morgan" rel="noopener noreferrer"&gt;Morgan&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/npm/npmlog" rel="noopener noreferrer"&gt;Npmlog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/winstonjs/winston" rel="noopener noreferrer"&gt;Winston&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For developers who want deeper visibility into API traffic with minimal setup, &lt;a href="https://www.moesif.com/wrap?onboard=true&amp;amp;utm_source=devto&amp;amp;utm_medium=bottom-cta&amp;amp;utm_content=how-we-built-nodejs-middleware" rel="noopener noreferrer"&gt;Moesif&lt;/a&gt; offers a seamless solution. Unlike traditional logging libraries, Moesif provides real-time API analytics, retention tracking, and security monitoring, making it an essential tool for scaling and optimizing API-driven applications.&lt;/p&gt;

</description>
      <category>node</category>
      <category>middleware</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>10 Error Status Codes When Building APIs For The First Time And How To Fix Them</title>
      <dc:creator>Moesif Staff</dc:creator>
      <pubDate>Thu, 20 Mar 2025 17:28:25 +0000</pubDate>
      <link>https://dev.to/moesif/10-error-status-codes-when-building-apis-for-the-first-time-and-how-to-fix-them-1cdg</link>
      <guid>https://dev.to/moesif/10-error-status-codes-when-building-apis-for-the-first-time-and-how-to-fix-them-1cdg</guid>
      <description>&lt;p&gt;When making your first API call, issues can arise, especially if you're new to API integration. It's common for documentation to lack details on API error status codes, as the focus is often on successful scenarios rather than potential problems.&lt;/p&gt;

&lt;p&gt;HTTP status codes provide insight into what occurred during your API call. These standardized codes range from 100 to 511, each with a specific meaning. However, only codes from 400 to 511 indicate an error response.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.moesif.com/features/api-analytics?utm_source=devto&amp;amp;utm_medium=top-cta&amp;amp;utm_term=10-error-status-codes" rel="noopener noreferrer"&gt;Moesif API Analytics&lt;/a&gt; can help track and analyze API errors in real-time, providing deep insights into API performance and response trends. This ensures developers can diagnose issues more effectively and optimize their API’s reliability.&lt;/p&gt;

&lt;p&gt;Let's explore the 10 most prevalent HTTP status codes that signal an error response, whether on the client or server side.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding HTTP Status Codes
&lt;/h2&gt;

&lt;p&gt;HTTP status codes are a crucial part of the HTTP protocol, used to convey the results of a client’s request. They are divided into five categories: informational responses, successful responses, redirection messages, client error responses, and server error responses. Understanding HTTP status codes is essential for developers, as they provide valuable information about the outcome of a request. By analyzing status codes, developers can identify errors, optimize their applications, and improve user experience.&lt;/p&gt;

&lt;p&gt;When you make an API call, the server responds with an HTTP status code that indicates whether the request was successful or if there was an issue. For instance, a 200 OK status code means the request was successful, while a 404 Not Found status code indicates that the requested resource could not be found. By familiarizing yourself with these codes, you can quickly diagnose problems and take appropriate action to resolve them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Error Types and Causes
&lt;/h2&gt;

&lt;p&gt;HTTP errors can be broadly classified into two categories: client-side errors and server-side errors. Client-side errors, such as 400 Bad Request, 401 Unauthorized, and 403 Forbidden, occur when the client’s request is invalid or cannot be processed by the server. These errors often result from issues like malformed request syntax, invalid authentication credentials, or insufficient permissions.&lt;/p&gt;

&lt;p&gt;On the other hand, server-side errors, such as 500 Internal Server Error, 502 Bad Gateway, and 503 Service Unavailable, occur when the server encounters an unexpected condition or is unable to fulfill the request. These errors can be caused by server overload, internal configuration errors, or issues with upstream services. Understanding the types and causes of errors is crucial for developers to diagnose and fix issues efficiently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Client-Side Status Codes
&lt;/h2&gt;

&lt;p&gt;Status codes in the 4XX range typically indicate client-side errors, though modifications to the API can also trigger them. These status codes inform the user agent about the nature of the error, guiding it to take specific actions such as retrying requests or modifying document views. Here are the 5 most common client-side status error codes and how to solve for them:&lt;/p&gt;

&lt;h3&gt;
  
  
  400 Bad Request: Malformed Request Syntax
&lt;/h3&gt;

&lt;p&gt;The &lt;em&gt;400 Bad Request&lt;/em&gt; error message is one of the most common HTTP status codes, indicating that your API request was not properly formatted. Deceptive request routing can also result in a 400 Bad Request error, as it involves malformed or invalid requests that the server cannot process. If no additional error details are provided in the response body, it's essential to consult the documentation. You might be missing a query parameter, a field in the request body, or there could be an error in a header field. Additionally, incorrect syntax in your request data could be the culprit.&lt;/p&gt;

&lt;p&gt;This differs from the &lt;em&gt;422 Unprocessable Entity&lt;/em&gt; error message, which occurs when your request is properly formatted but cannot be processed.&lt;/p&gt;

&lt;h3&gt;
  
  
  403 Forbidden
&lt;/h3&gt;

&lt;p&gt;403 Forbidden status indicates that you lack the necessary permissions to access the requested URL. Although you are authenticated, the user or role associated with your credentials is not authorized to perform the API request.&lt;/p&gt;

&lt;p&gt;This error may also occur due to authentication problems, such as using an incorrect API key or attempting to access features not included in your subscription plan. To avoid a 403 Forbidden error and gain network access, ensure proper authentication.&lt;/p&gt;

&lt;h3&gt;
  
  
  404 Not Found
&lt;/h3&gt;

&lt;p&gt;The 404 Not Found error is among the most frequent HTTP status codes encountered. It signifies that the URL specified in your request is not available on the API server or the origin server. Although categorized as a 4XX error, typically indicating a client-side issue, it can also suggest a problem on the server's end. Changes in API URL paths after a version update or server-related issues can lead to this error.&lt;/p&gt;

&lt;p&gt;Errors from a prior request might also trigger a 404 Not Found error, particularly if earlier interactions resulted in state management problems between requests.&lt;/p&gt;

&lt;p&gt;To address this, first verify for typos in your client code, then investigate potential API issues.&lt;/p&gt;

&lt;p&gt;This status code further implies that you haven't authenticated with the API. The API is unable to identify you and, therefore, cannot fulfill your request.&lt;/p&gt;

&lt;p&gt;Usually, you need to register and obtain an API key for most APIs. This key should be included in an HTTP header field when making a request to inform the API of your identity.&lt;/p&gt;

&lt;p&gt;This HTTP status code is akin to the less common &lt;em&gt;407 Proxy Authentication Required&lt;/em&gt;, which indicates a lack of authentication with the proxy.&lt;/p&gt;

&lt;h3&gt;
  
  
  429 Too Many Requests
&lt;/h3&gt;

&lt;p&gt;API subscription plans often have usage limits, with lower-cost options allowing fewer requests per second for your API key. If you're sending too many requests quickly, consider implementing throttling in your client. Request headers can dictate conditions that affect rate limits and response behavior, including status codes like 412 (Precondition Failed) and 304 (Not Modified). This response might also indicate you've reached a daily, weekly, or monthly limit on your account. Without utilizing API analytics, you might hit these limits without receiving notifications or alerts.&lt;/p&gt;

&lt;p&gt;An API might seem ideal until you encounter its limitations, which can render it unsuitable for your needs. It's crucial to understand your API subscription details before integration to avoid potential issues down the line.&lt;/p&gt;

&lt;h2&gt;
  
  
  Server-Side Status Codes
&lt;/h2&gt;

&lt;p&gt;The 5XX range of status codes typically indicates server-side errors, although sometimes an invalid API call that should result in a 4XX error might instead return a 5XX error if not properly handled by the server. Here are the five most common server-side errors and how to resolve them:&lt;/p&gt;

&lt;h3&gt;
  
  
  500 Internal Server Error
&lt;/h3&gt;

&lt;p&gt;This HTTP status code can mean anything really, but it usually indicates the API server crashed. It could have been caused by something related to your API call. A 500 error can also occur if the server encounters issues with the message body during content negotiation.&lt;/p&gt;

&lt;p&gt;Double-check the docs to make sure you did everything right: query fields, body fields, headers, and format.&lt;/p&gt;

&lt;p&gt;If the issue persists, it could be due to an API update that introduced problematic code or data from an upstream service. In such cases, your best course of action is to contact the API's support team for&lt;/p&gt;

&lt;h3&gt;
  
  
  501 Not Implemented
&lt;/h3&gt;

&lt;p&gt;The &lt;em&gt;501 Not Implemented&lt;/em&gt; status code relates to the HTTP method used to request a URL. To resolve this, try using a different HTTP method for your request.&lt;/p&gt;

&lt;p&gt;Some response codes, like 501, dictate that the user agent will continue using the same HTTP method from the prior request.&lt;/p&gt;

&lt;p&gt;Typically, an HTTP request using an incorrect method results in a 404 Not Found status. A Not Implemented status, however, suggests that the method is not available "yet." This status allows the API creator to inform clients that this method will be accessible in future requests.&lt;/p&gt;

&lt;h3&gt;
  
  
  502 Bad Gateway
&lt;/h3&gt;

&lt;p&gt;This response indicates that the server you contacted was not the actual API server but rather a gateway or proxy. The proxy server attempts to communicate with the API server on your behalf. This error response also suggests that the API server did not respond. This could be due to a network issue, the API server crashing, or it being down for maintenance.&lt;/p&gt;

&lt;p&gt;A 502 error indicates that the proxy server could not get the requested response from the API server.&lt;/p&gt;

&lt;p&gt;A "bad gateway" error is generally a temporary issue and should be addressed by the API provider. However, if the problem continues, it's advisable to contact their support team for assistance.&lt;/p&gt;

&lt;h3&gt;
  
  
  503 Service Unavailable
&lt;/h3&gt;

&lt;p&gt;The 503 Service Unavailable status signifies a server error. This typically occurs when the server is overwhelmed by too many API requests and cannot handle additional ones. While this issue may resolve itself as clients reduce the number of future requests, it might also indicate that the API provider hasn't allocated sufficient resources.&lt;/p&gt;

&lt;p&gt;Request headers can influence the server's response behavior, potentially leading to a 503 error if certain conditions are not met.&lt;/p&gt;

&lt;p&gt;To enhance your client's resilience against this error, consider implementing a delay before sending another request. However, if the error code persists, it's crucial to reach out to the API provider for further assistance.&lt;/p&gt;

&lt;h3&gt;
  
  
  504 Gateway Timed Out
&lt;/h3&gt;

&lt;p&gt;Similar to the 502 Bad Gateway status, this response code indicates that the server you're contacting is acting as a proxy for the actual API server. In this case, the issue lies with the API server's delayed response.&lt;/p&gt;

&lt;p&gt;This could be related to high network latency between the proxy and the API server. It could also mean that the API server takes too long to process your request. Additionally, a 504 error can occur when a user agent requested content that the server cannot provide due to slow response times.&lt;/p&gt;

&lt;p&gt;To address this issue, examine whether the content of your request might be contributing to the timeout. If you are requesting an excessive amount of data or performing a calculation that takes an extended time, consider minimizing the request.&lt;/p&gt;

&lt;p&gt;If you think your request is reasonable and the status doesn’t go away, contact support.&lt;/p&gt;

&lt;h2&gt;
  
  
  Best Practices for Error Handling
&lt;/h2&gt;

&lt;p&gt;Error handling is a critical aspect of web development, and best practices can help developers handle errors effectively. Here are some best practices for error handling:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use meaningful error messages&lt;/strong&gt;: Provide clear and concise error messages that help users understand what went wrong. Avoid generic messages like “An error occurred” and instead offer specific details about the issue.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Log errors&lt;/strong&gt;: Log errors to track and analyze issues, and to identify patterns and trends. This can help you pinpoint recurring problems and address them proactively. &lt;a href="https://www.moesif.com/features/api-analytics?utm_source=devto&amp;amp;utm_medium=top-cta&amp;amp;utm_term=10-error-status-codes" rel="noopener noreferrer"&gt;Moesif API Analytics&lt;/a&gt; can help streamline this process by providing detailed logs and filtering capabilities to detect anomalies.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use error codes&lt;/strong&gt;: Use standardized error codes, such as HTTP status codes, to convey error information. This makes it easier for developers to understand and troubleshoot issues.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Handle errors centrally&lt;/strong&gt;: Handle errors centrally, using a single error handling mechanism, to simplify error handling and reduce code duplication. This approach ensures consistency and makes it easier to manage errors across your application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Test error handling&lt;/strong&gt;: Test error handling mechanisms thoroughly to ensure they work as expected. Simulate different error scenarios to verify that your application responds appropriately and provides useful feedback to users.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By integrating &lt;a href="https://www.moesif.com/features/api-monitoring?utm_source=devto&amp;amp;utm_medium=top-cta&amp;amp;utm_term=10-error-status-codes" rel="noopener noreferrer"&gt;Moesif API Monitoring&lt;/a&gt;, developers can receive real-time alerts on critical API failures, ensuring that error handling mechanisms are optimized and efficient.&lt;/p&gt;

&lt;h2&gt;
  
  
  Error Prevention Strategies
&lt;/h2&gt;

&lt;p&gt;Preventing errors is always better than handling them. Here are some strategies to prevent errors:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Validate user input&lt;/strong&gt;: Validate user input to prevent malformed requests and reduce the risk of errors. Ensure that all required fields are present and that the data is in the correct format.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use caching&lt;/strong&gt;: Use caching to reduce the load on servers and prevent errors caused by high traffic. Caching can improve performance and reduce the likelihood of server overload.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Optimize database queries&lt;/strong&gt;: Optimize database queries to prevent errors caused by slow or inefficient queries. Use indexing, query optimization techniques, and database tuning to improve query performance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use load balancing&lt;/strong&gt;: Use load balancing to distribute traffic evenly and prevent errors caused by server overload. Load balancing can help ensure that your application remains responsive even under heavy load.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Monitor performance&lt;/strong&gt;: Monitor performance regularly to identify potential issues and prevent errors. Use monitoring tools to track key metrics and set up alerts for unusual activity.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By implementing these strategies, you can reduce the likelihood of errors and ensure a smoother experience for your users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monitoring HTTP Status Codes With Moesif
&lt;/h2&gt;

&lt;p&gt;Moesif offers comprehensive &lt;a href="https://www.moesif.com/features/api-monitoring?utm_campaign=Int-site&amp;amp;utm_source=devto&amp;amp;utm_medium=body-cta&amp;amp;utm_content=10-error-status-codes" rel="noopener noreferrer"&gt;monitoring and notification&lt;/a&gt; features, enabling you to automatically track any HTTP status code errors and gain valuable insights from your error response patterns.&lt;/p&gt;

&lt;p&gt;With &lt;strong&gt;real-time error alerts&lt;/strong&gt;, &lt;a href="https://www.moesif.com/features/api-monitoring?utm_source=devto&amp;amp;utm_medium=top-cta&amp;amp;utm_term=10-error-status-codes" rel="noopener noreferrer"&gt;Moesif API Monitoring&lt;/a&gt; helps identify critical issues before they impact users, allowing teams to proactively resolve them. Whether it’s a spike in 500 Internal Server Errors or unexpected 429 rate-limit errors, Moesif ensures you stay informed with actionable notifications.&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%2Fukdh11sy9rufbag02nou.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%2Fukdh11sy9rufbag02nou.png" alt="Dashbaords showing 4xx and 5xx error trends" width="800" height="460"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;API calls are consistently monitored with user identity, facilitating the swift identification and resolution of errors.&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%2Fumx5d7z74pmj993b597w.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%2Fumx5d7z74pmj993b597w.png" alt="Automatic altering for status code" width="723" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Undoubtedly, you’ll see many error codes when using APIs, but most have reasonable fixes. Some are related to server errors and some to client-side errors, where often one can cause the other. Request headers allow clients to customize their HTTP requests and influence the server's response behavior.&lt;/p&gt;

&lt;p&gt;Make sure to thoroughly read the documentation and API notes to avoid missing any crucial details during integration. If issues persist, reach out to the API provider for assistance.&lt;/p&gt;

&lt;p&gt;Sometimes, the API provider may not resolve an issue for a consumer. If you're using a widely-used API, consider searching online for solutions, particularly on &lt;a href="https://stackoverflow.com/" rel="noopener noreferrer"&gt;StackOverflow&lt;/a&gt; or generative artificial intelligence chatbot's like &lt;a href="https://chatgpt.com/" rel="noopener noreferrer"&gt;ChatGPT&lt;/a&gt;, to find a fix for your error responses. Stay determined, and you’ll see your 200 OK status codes in no time.&lt;/p&gt;

</description>
      <category>api</category>
      <category>apimonitoring</category>
      <category>apistatuscode</category>
      <category>realtimeerroralerts</category>
    </item>
    <item>
      <title>Why a Unified View of API Usage is Critical for Managing Multiple API Gateways</title>
      <dc:creator>Moesif Staff</dc:creator>
      <pubDate>Tue, 04 Mar 2025 14:31:55 +0000</pubDate>
      <link>https://dev.to/moesif/why-a-unified-view-of-api-usage-is-critical-for-managing-multiple-api-gateways-337n</link>
      <guid>https://dev.to/moesif/why-a-unified-view-of-api-usage-is-critical-for-managing-multiple-api-gateways-337n</guid>
      <description>&lt;p&gt;APIs have become the backbone of our digital world, with surveys showing that &lt;a href="https://www.postman.com/state-of-api/2024" rel="noopener noreferrer"&gt;over 70% of developers plan to increase API usage year-over-year&lt;/a&gt;. They power everything from mobile apps and SaaS integrations to IoT devices and partner platforms, enabling businesses to deliver seamless services and experiences to customers. As organizations grow, however, so does the complexity of their API ecosystem. Many teams end up deploying multiple API gateways, often to manage different product lines, microservices, or regional deployments.&lt;/p&gt;

&lt;p&gt;While multiple gateways can offer flexibility and specialized features, they also create new challenges. Each gateway might have its own monitoring dashboards, security configurations, documentation portals, and analytics tools. Product managers, developers, and operational teams quickly find themselves juggling scattered bits of data as they attempt to track API usage, performance metrics, and monetization results across these disparate solutions.&lt;/p&gt;

&lt;p&gt;That’s why forward-thinking organizations are turning to &lt;strong&gt;unified API management for multiple API gateways&lt;/strong&gt;. By consolidating data from all their gateways into a &lt;strong&gt;single source of truth&lt;/strong&gt;, they gain the ability to track both operational KPIs (like uptime and error rates) and business KPIs (like usage growth and revenue impact) from one shared dashboard. This not only streamlines troubleshooting and optimization but also enables product managers to “package” their APIs effectively whether for new subscription tiers, developer-friendly bundles, or usage-based pricing models.&lt;/p&gt;

&lt;p&gt;Let's explore the reasons organizations end up with multiple API gateways, the pitfalls and pain points they encounter, and the specific benefits that a unified approach can deliver. Along the way, you’ll see how incorporating centralized analytics and leveraging platforms like &lt;strong&gt;Moesif&lt;/strong&gt;, can help unravel the complexity, drive better decisions, and ultimately boost your bottom line.&lt;/p&gt;

&lt;h2&gt;
  
  
  Unified API Management for Multiple API Gateways: Why They Exist in an Organization
&lt;/h2&gt;

&lt;p&gt;For many organizations, having multiple API gateways isn’t necessarily an intentional design choice. Instead, it often evolves organically over time as the business scales or adapts to new requirements. Here are a few common scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Organic Growth Across Teams&lt;/strong&gt;: Teams select API gateways based on their specific needs, leading to multiple “best-of-breed” gateways operating in parallel.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Mergers and Acquisitions&lt;/strong&gt;: Companies inherit different API infrastructures and maintain multiple gateways to ensure compatibility and avoid integration disruptions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Varied Deployment Environments&lt;/strong&gt;: Different regions require specialized gateways for compliance, data sovereignty, or latency optimization (e.g., GDPR in the EU, domestic payment systems in the U.S.).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Specialized Use Cases&lt;/strong&gt;: Internal microservices may use lightweight gateways, while customer-facing APIs require advanced features like authentication flows and developer portals.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An API management solution can help manage the complexities of having multiple API gateways by providing a flexible protocol that allows businesses to switch between different gateways without needing to rework their developer portal. This enhances integration and functionality across the organization.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem and Why It Matters
&lt;/h3&gt;

&lt;p&gt;Although multiple gateways can serve unique demands, it quickly becomes tricky to manage. Teams end up with fragmented data on API usage, performance, and developer adoption. Each gateway might provide its own analytics dashboard, making cross-team collaboration and strategic decision-making difficult.&lt;/p&gt;

&lt;p&gt;Without a unified view across these gateways, product managers and leadership struggle to see which APIs are truly driving revenue, where traffic is spiking, or how user onboarding differs from one product line to another. In fact, recent research shows that &lt;a href="https://www.salesforce.com/news/stories/connectivity-report-2023/" rel="noopener noreferrer"&gt;38% of revenue-generating digital assets in enterprises are API-driven&lt;/a&gt;, making visibility across multiple gateways critical. Let’s dive deeper into these challenges and how a consolidated approach can save organizations from operational headaches while unlocking valuable new business insights. A developer portal can help manage these issues by providing a seamless interface with various API gateways, enabling fast key provisioning and integration, and offering a unified view that simplifies the evaluation process for API management solutions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Challenges of Managing Multiple API Gateways and the Power of Unified API Management
&lt;/h2&gt;

&lt;p&gt;As organizations scale, different teams, business units, or regions may adopt various API gateways based on their unique requirements—whether for performance, security, compliance, or regional deployment. While this flexibility allows for tailored solutions, it also introduces operational inefficiencies, governance inconsistencies, and fragmented data visibility. Without a unified approach, companies struggle to optimize API performance, enforce security policies, and drive monetization strategies effectively. API providers can help manage these challenges by offering centralized solutions that streamline operations, enhance security, and create new revenue streams through various pricing models like pay-per-use and partnerships.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Hidden Costs of API Fragmentation
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Data Silos and Limited Insights&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Inconsistent API Metrics&lt;/strong&gt;: Each gateway provides separate analytics, making it difficult to gain a comprehensive view of API usage, performance, and adoption trends.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Difficult Monetization Tracking&lt;/strong&gt;: API monetization models vary across gateways, leading to inconsistent revenue tracking and missed optimization opportunities.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Understanding API users can help overcome data silos and gain better insights by enriching user profiles and analyzing API usage alongside revenue and customer success.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Limited Business Visibility and Growth Potential&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Unclear API Adoption Metrics&lt;/strong&gt;: Understanding customer behavior and high-value integrations is challenging when data remains siloed. Tracking API usage growth can help improve business visibility and growth potential by identifying trends and ensuring consistent usage over time.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Hindered API Packaging Strategies&lt;/strong&gt;: Product managers lack the insights needed to refine pricing tiers, subscription models, and usage-based billing structures.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Solution: A Unified View for API Management
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;unified API management strategy&lt;/strong&gt; eliminates these challenges by consolidating API analytics, governance, and monetization tools into a single platform. Moesif provides deep visibility into API performance, security, and usage patterns across multiple gateways, empowering teams to make data-driven decisions and maximize API business potential. API management solutions can provide a unified view for API management, offering innovative features and developer portals that are essential for organizations, especially in multi-gateway environments.&lt;/p&gt;

&lt;h3&gt;
  
  
  Holistic API Observability and Governance
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Real-Time API Monitoring&lt;/strong&gt;: &lt;a href="https://www.moesif.com/features/api-analytics?utm_source=blog&amp;amp;utm_medium=content-link&amp;amp;utm_content=DEVTO-Unified-View-of-API-Usage" rel="noopener noreferrer"&gt;Moesif can aggregate usage and performance metrics&lt;/a&gt; from multiple API gateways, enabling rapid issue detection and resolution. Monitoring CPU and memory usage can help in holistic API observability and governance by providing insights into application responsiveness and server health, which are crucial for resource planning and diagnosing performance issues.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Standardized Security Policies&lt;/strong&gt;: &lt;a href="https://www.moesif.com/features/api-governance-rules?utm_source=blog&amp;amp;utm_medium=content-link&amp;amp;utm_content=DEVTO-Unified-View-of-API-Usage" rel="noopener noreferrer"&gt;Enforce rate limiting&lt;/a&gt; and compliance requirements consistently across all API deployments.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Smarter Monetization and Product Strategy
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cross-Gateway API Insights&lt;/strong&gt;: Product managers can analyze API adoption, revenue impact, and retention rates in a single unified view within Moesif.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Optimized Pricing and Billing&lt;/strong&gt;: Gain the intelligence needed to refine monetization models, implement tiered pricing, and maximize API revenue. Understanding the API product lifecycle can further enhance these strategies by providing insights into key performance indicators relevant to business impact and operational success.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Aligning Business Goals with API Strategy
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Unified KPI Tracking&lt;/strong&gt;: Moesif enables organizations to track API performance, customer engagement, and bxusiness impact through a single analytics platform with &lt;a href="https://www.moesif.com/features/api-dashboards?utm_source=blog&amp;amp;utm_medium=content-link&amp;amp;utm_content=DEVTO-Unified-View-of-API-Usage" rel="noopener noreferrer"&gt;custom API dashboards&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scalable API Growth&lt;/strong&gt;: Centralized visibility into API usage trends supports infrastructure planning and expansion strategies.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With Moesif, companies can transform chaotic, multi-gateway environments into streamlined, data-driven ecosystems that enhance developer experience, improve security, and drive new revenue opportunities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Unified Analytics Help Product Managers Package and Monetize APIs
&lt;/h2&gt;

&lt;p&gt;When an organization has visibility into &lt;strong&gt;who&lt;/strong&gt; is using their APIs, &lt;strong&gt;how&lt;/strong&gt; they’re using them, and &lt;strong&gt;why&lt;/strong&gt; they’re valuable, it becomes far easier to design effective pricing and packaging strategies. This is where unified analytics across multiple gateways truly shines. Let’s explore how product managers can leverage this holistic data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Segmenting and Identifying High-Value API Usage
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Usage Segmentation&lt;/strong&gt;: Aggregating data across gateways helps segment usage by customer tiers, feature adoption, or endpoint activity. If enterprise customers heavily rely on a particular API, it may justify premium pricing or SLAs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Customer Profiling&lt;/strong&gt;: Understanding which customers generate the highest traffic or revenue allows for better API packaging and monetization strategies.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Optimizing Pricing, Packaging, and Monetization
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Subscription vs. Pay-Per-Use&lt;/strong&gt;: A clear view of API consumption enables Product Managers to choose the right pricing model—subscriptions for predictable costs or pay-per-use for flexibility.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Feature-Based Monetization&lt;/strong&gt;: Advanced features, such as analytics or premium data, can be placed in higher-tier plans based on real usage data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Multi-API Bundles &amp;amp; Upsell Paths&lt;/strong&gt;: Bundling related APIs and tracking usage thresholds can drive upsells, ensuring that developers move into higher tiers when they exceed their limits.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Data-Driven Adjustments and Transparency
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Real-Time Optimization&lt;/strong&gt;: A unified view allows for quick adjustments to pricing and packaging based on under or overutilized features.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Promotional Campaign Tracking&lt;/strong&gt;: Integrated analytics provide insights into how trials or promotions impact usage, guiding future marketing efforts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Clear Metering &amp;amp; Billing Transparency&lt;/strong&gt;: Giving customers visibility into their API usage reduces billing disputes and builds trust, while automated alerts prevent unexpected overages.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A singular view of usage is a powerful enabler for API productization and monetization. It provides the granular insights product managers need to craft compelling offers, set competitive pricing, and nurture stronger relationships with customers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key API Metrics: Why a Unified View Matters
&lt;/h2&gt;

&lt;p&gt;Bringing together multiple API gateways under one management framework grants you the power to observe performance, reliability, and revenue-generation in a consistent, holistic way. These &lt;strong&gt;key metrics&lt;/strong&gt; form the bedrock of continuous improvement, helping you spot bottlenecks, optimize resource allocation, and validate strategic decisions. Increased API usage is a key metric for understanding API performance and customer engagement.&lt;/p&gt;

&lt;h3&gt;
  
  
  Product and Business KPIs
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Revenue or Billing Metrics&lt;/strong&gt;: For monetized APIs, track revenue per call, average revenue per user (ARPU), and churn rates. These metrics can confirm whether your pricing models and product tiers are viable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Conversion Rates&lt;/strong&gt;: If you offer freemium or trial tiers, measure how many developers or businesses upgrade to paid plans. This indicates how compelling your paid features are and where you might refine your funnel.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Feature Adoption&lt;/strong&gt;: Monitor usage of key endpoints or functionalities. Understanding which features gain the most traction guides future roadmap decisions and helps you prioritize improvements that yield the highest ROI.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Adoption and Usage Metrics
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;API Call Distribution&lt;/strong&gt;: With multiple gateways, it’s vital to see how traffic is distributed across various services and endpoints. This reveals which APIs are under heavy load or show strong growth potential.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;New vs. Returning Developers&lt;/strong&gt;: A unified view of developer onboarding metrics—like time-to-first-successful-call or repeat usage—indicates how well your APIs retain interest and whether your documentation or portals are effective.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Geographical/Regional Usage&lt;/strong&gt;: Tracking where calls originate can guide infrastructure decisions (e.g., data center locations) and help you tailor security policies for each region.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Latency (Average and Peak)&lt;/strong&gt;: Monitoring response times is crucial for ensuring a seamless end-user experience. High latency can signal underlying issues in either the gateway configurations or your backend services. In fact, &lt;a href="https://www.cloudflare.com/en-ca/2024-api-security-management-report/" rel="noopener noreferrer"&gt;Cloudflare’s API Performance Report&lt;/a&gt; shows that 57% of internet traffic is now composed of API requests, making speed and efficiency a top priority.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Error Rates&lt;/strong&gt;: Tracking the frequency and type of errors (4XX, 5XX) helps surface potential configuration problems, code bugs, or external dependencies failing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Throughput and Request Volume&lt;/strong&gt;: By understanding how many requests each gateway handles—and during which time frames—you can proactively manage capacity, load balance effectively, and predict scaling needs.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In a multi-gateway environment, relying on fragmented statistics can lead to misinformed decisions. A unified dashboard ensures every team, from product management to engineering, has the data they need to troubleshoot issues, iterate on features, and prove ROI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Business and Growth: Why You Need a Unified Dashboard
&lt;/h2&gt;

&lt;p&gt;While operational stability and a strong developer experience are vital, most organizations ultimately measure API success by its impact on the &lt;strong&gt;bottom line&lt;/strong&gt; and long-term &lt;strong&gt;market positioning&lt;/strong&gt;. A unified API strategy can serve as a foundation for sustainable growth, allowing product teams to focus on strategic initiatives rather than firefighting.&lt;/p&gt;

&lt;h3&gt;
  
  
  Customer Acquisition and Retention
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Targeted Upsell/Cross-Sell&lt;/strong&gt;: By analyzing usage across gateways, you can identify which customers or partners might benefit from additional API features or higher-tier plans. Automated alerts or in-app notifications can then prompt timely upsells, increasing average revenue per user.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reduced Churn through Insights&lt;/strong&gt;: A single pane of glass for customer activity enables quick identification of at-risk accounts—e.g., a sudden drop in API calls could signal dissatisfaction or technical hurdles. Product managers can intervene proactively, offering support or new features to keep users engaged.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Strategic Growth and Market Expansion
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data-Backed Roadmap Decisions&lt;/strong&gt;: Comprehensive usage data drives more accurate prioritization of new features, expansions, or acquisitions. Leadership can see precisely which APIs or endpoints are fueling growth—and invest accordingly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Confident Expansion into New Markets&lt;/strong&gt;: If the data shows strong traction in a specific region or industry, leadership can allocate resources strategically, designing localized solutions or forging new partnerships.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Preparing for Emerging Business Models&lt;/strong&gt;: Whether it’s launching new subscription tiers or integrating with ecosystem partners, a unified API platform makes it simpler to experiment with—and measure—new revenue models.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Staying Agile in Fast-Changing Markets&lt;/strong&gt;: Unified metrics and streamlined workflows help your teams pivot quickly in response to market feedback or disruptive trends, ensuring long-term competitiveness.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cross-Functional Visibility and Scalable Collaboration
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Single Source of Truth for Stakeholders&lt;/strong&gt;: When executives, product managers, and DevOps share the same metrics, conversations shift from “do we have the data?” to “how do we use it?” This alignment empowers better coordination on product strategy, sales, and support.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bridging Silos in Large Organizations&lt;/strong&gt;: In multi-division or globally distributed companies, a unified approach ensures that successes and challenges are visible across the organization, reducing duplication of effort and fostering synergy.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scalable Growth and Future-Proofing&lt;/strong&gt;: A well-structured API management strategy ensures that teams can scale efficiently, breaking down data silos and creating a foundation for long-term business growth.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Centralized API management isn’t just about operational efficiency; it’s also a strategic growth lever. When teams have clear, unified data on API usage and performance, they can make stronger decisions about product direction, pricing strategies, and market expansion. In the next section, we’ll discuss how these elements come together in real-world scenarios, using unified analytics to maximize both technical efficiency and business ROI.&lt;/p&gt;

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

&lt;p&gt;From the moment an organization deploys its first API gateway to the point where dozens of microservices and product lines are live, the complexity of managing and measuring API usage can grow exponentially. Multiple gateways, each with its own analytics and operational quirks, can easily lead to data silos and fragmented insights. Yet by &lt;strong&gt;consolidating&lt;/strong&gt; these gateways under a single lens, companies unlock new levels of transparency and control.&lt;/p&gt;

&lt;p&gt;While each organization’s path to unified API management is unique, the overarching takeaway remains constant: &lt;strong&gt;centralizing your API data is a multiplier on success&lt;/strong&gt;. It nurtures a holistic understanding of user behavior, helps maintain strong SLAs, and aligns teams around shared, data-driven goals.&lt;/p&gt;

&lt;p&gt;If you’re exploring solutions in this space, Moesif is capable of providing deep insights into both the operational and business aspects of your APIs. The key is to find tools and processes that facilitate, rather than hinder, your multi-gateway strategy. &lt;a href="https://www.moesif.com/wrap?onboard=true&amp;amp;utm_source=blog&amp;amp;utm_medium=bottom-cta&amp;amp;utm_content=DEVTO-Unified-View-of-API-Usage" rel="noopener noreferrer"&gt;Sign up today for a free trial&lt;/a&gt;, no credit card required.&lt;/p&gt;

</description>
      <category>api</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Best Practices for Monetizing AI Successfully</title>
      <dc:creator>Moesif Staff</dc:creator>
      <pubDate>Tue, 25 Feb 2025 14:49:13 +0000</pubDate>
      <link>https://dev.to/moesif/best-practices-for-monetizing-ai-successfully-356n</link>
      <guid>https://dev.to/moesif/best-practices-for-monetizing-ai-successfully-356n</guid>
      <description>&lt;p&gt;Artificial intelligence has become a driving force behind modern innovation, helping businesses across all industries optimize processes and generate income. But how do you monetize AI usage effectively? Whether you’re integrating AI features into an existing plan or launching entirely new AI products, choosing the right approach can unlock steady revenue growth and strengthen competitive advantage.&lt;/p&gt;

&lt;p&gt;In this article, we’ll explore several proven monetization strategies for artificial intelligence, from direct monetization to indirect monetization, and shed light on developing an AI pricing strategy that suits your target audience. We’ll also highlight best practices for defining value metrics, managing cost structures, and building long-term customer satisfaction. By the end, you’ll see how even a significant investment in AI can be recouped through the right pricing model and thoughtful execution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding AI Monetization
&lt;/h2&gt;

&lt;p&gt;“Monetizing AI” involves generating revenue from artificial intelligence tools, such as AI-powered tools, AI chatbots, or AI-enhanced analytics. To effectively monetize AI usage, businesses typically offer AI capabilities—such as NLP, computer vision, or large language models—as paid features or standalone solutions that deliver actual value to customers.&lt;/p&gt;

&lt;p&gt;Businesses can adopt a variety of monetization strategies, including usage-based pricing, bundled pricing, or a value-led pricing strategy. Regardless of the approach, the key is to determine how much value your AI functionalities bring to users and to align pricing with that actual usage. Doing so ensures customers feel they’re paying the right price point for the benefits they receive.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is AI Monetization?
&lt;/h3&gt;

&lt;p&gt;AI monetization refers to the process of generating revenue from artificial intelligence (AI) capabilities, features, and products. This involves developing and implementing effective pricing strategies, packaging, and licensing models to capture the value created by AI. For businesses, AI monetization is critical to recoup their investments in AI research, development, and deployment. By strategically leveraging AI capabilities, companies can unlock new revenue streams, enhance customer experiences, and maintain a competitive edge in the market.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why It Matters
&lt;/h3&gt;

&lt;p&gt;Monetizing AI is more than just an opportunity—it's quickly becoming a necessity for businesses looking to stay competitive. AI is reshaping industries by improving efficiency, personalizing customer experiences, and driving automation. However, understanding how to extract real monetary value from AI investments is a challenge that many businesses face. By leveraging the right strategies, companies can ensure that their AI innovations not only enhance operations but also contribute directly to revenue growth.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;AI can reduce manual labor and handle complex tasks that would otherwise require human intelligence. By automating repetitive processes, AI allows employees to focus on higher-value work, leading to increased productivity and cost savings. Additionally, AI-driven automation can scale operations more efficiently, handling large volumes of data-driven tasks without the need for proportional increases in workforce size.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;AI uncovers insights in usage data for better decision-making and customer behavior analysis. By leveraging machine learning algorithms, businesses can detect patterns, predict future trends, and personalize customer interactions. AI-driven analytics can provide real-time feedback, allowing organizations to refine marketing strategies, optimize pricing models, and enhance customer segmentation for maximum impact.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Many organizations incorporate generative AI (e.g., AI-generated art) to differentiate their offerings. This includes leveraging AI to create unique marketing assets, generate personalized content at scale, and develop innovative digital products that stand out in competitive markets. Additionally, businesses are using AI to streamline creative workflows, reducing costs and enhancing efficiency in content production.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ultimately, artificial intelligence can be a significant investment. However, with proper planning and a well-defined AI monetization strategy, it becomes easier to monetize AI usage and see a return on that investment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Trends in AI Monetization
&lt;/h3&gt;

&lt;p&gt;The AI monetization landscape is rapidly evolving, with several key trends emerging. Businesses are continuously exploring innovative ways to capitalize on AI's capabilities, from advanced pricing models to AI-driven market analysis. As AI adoption increases across industries, companies must stay ahead of these trends to maintain a competitive edge and unlock new revenue streams.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Hybrid Pricing Models&lt;/strong&gt;: Companies are increasingly adopting hybrid pricing models that combine subscription-based, usage-based, and tiered pricing. This approach allows businesses to capture the value of AI features and products more effectively by aligning pricing with customer usage and needs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Value-Based Pricing&lt;/strong&gt;: AI vendors are shifting towards value-based pricing, where the price of AI features and products is tied to the actual value they deliver to customers. This ensures that customers perceive they are getting their money’s worth, fostering long-term satisfaction and loyalty.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AI-Powered Pricing Optimization&lt;/strong&gt;: Companies are leveraging AI-powered pricing optimization tools to analyze customer behavior, market trends, and competitor pricing. These tools help businesses fine-tune their AI pricing strategies, ensuring they remain competitive while maximizing revenue.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Increased Focus on Customer Lifetime Value&lt;/strong&gt;: AI vendors are prioritizing customer lifetime value (CLV) as a key metric to measure the success of their AI monetization strategies. By focusing on CLV, companies can develop strategies that enhance customer retention and drive long-term profitability.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By taking a structured approach to AI monetization, businesses can harness the full potential of their AI investments. Whether through direct revenue models, data-driven insights, or enhanced customer experiences, AI presents numerous opportunities to generate income and improve operational efficiency. The key lies in selecting the right strategy, continuously optimizing offerings, and adapting to market trends to stay ahead of the competition.&lt;/p&gt;

&lt;h2&gt;
  
  
  Identifying AI Capabilities
&lt;/h2&gt;

&lt;p&gt;Identifying AI capabilities is crucial for developing effective AI monetization strategies. Understanding the full range of AI functionalities allows businesses to leverage these technologies in innovative ways, enhancing both operational efficiency and revenue potential. By identifying AI capabilities, companies can better align their offerings with customer needs, optimize pricing structures, and create unique value propositions that set them apart in competitive markets. AI capabilities can be categorized into several types, including:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Machine Learning&lt;/strong&gt;: Machine learning capabilities enable AI systems to learn from data and improve their performance over time. This can be applied in various domains, from predictive maintenance to personalized recommendations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Natural Language Processing&lt;/strong&gt;: Natural language processing (NLP) capabilities enable AI systems to understand and generate human language. This is essential for applications like chatbots, virtual assistants, and sentiment analysis.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Computer Vision&lt;/strong&gt;: Computer vision capabilities enable AI systems to interpret and understand visual data from images and videos. This technology is used in areas such as facial recognition, autonomous vehicles, and medical imaging.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Predictive Analytics&lt;/strong&gt;: Predictive analytics capabilities enable AI systems to analyze data and make predictions about future outcomes. This is valuable for applications like demand forecasting, risk assessment, and customer behavior analysis.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Large Language Models (LLMs)&lt;/strong&gt;: LLMs enable AI systems to process and generate human-like text, facilitating advanced applications like conversational AI, content creation, and automated code generation. These models are widely used in virtual assistants, customer service automation, and knowledge management solutions.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By staying informed about emerging AI trends and continuously refining strategies, businesses can maximize the value of their AI investments. The evolving landscape of AI presents endless opportunities, and companies that adopt a proactive approach will be best positioned for long-term success.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI Features and Products
&lt;/h2&gt;

&lt;p&gt;AI features and products can be monetized in various ways, including leveraging AI-driven automation, enhancing existing services with intelligent capabilities, and integrating AI-powered insights into business operations. Companies can implement diverse strategies to create new revenue streams, expand market reach, and differentiate their offerings from competitors.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Direct Monetization&lt;/strong&gt;: Charging customers directly for AI features and products through one-time purchases, subscriptions, or pay-per-use models. Businesses can implement this by offering premium AI functionalities, API access, or AI-driven enhancements as paid upgrades. Additionally, companies can monetize AI through licensing agreements, enterprise contracts, and tiered service offerings that provide advanced capabilities for higher fees. The flexibility of direct monetization allows organizations to tailor pricing structures to customer needs while ensuring a steady revenue stream from AI innovations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Indirect Monetization&lt;/strong&gt;: Generating revenue from AI features and products through indirect channels, such as advertising, data analytics, or strategic partnerships. Businesses can leverage AI to enhance targeted marketing campaigns, optimize customer insights for improved engagement, and create AI-driven solutions that drive customer retention. Additionally, companies can monetize AI by offering data-driven insights to third parties, providing enhanced analytics for advertisers, or integrating AI-powered recommendations into existing services to increase value without direct fees.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Freemium Models&lt;/strong&gt;: Offering basic AI features and products for free while charging customers for premium features and products. This approach allows businesses to attract a large user base and demonstrate the value of their AI-driven services. Free-tier users can experience core functionalities, increasing the likelihood of upgrading to paid tiers for advanced capabilities, enhanced performance, or additional integrations. Many successful AI companies use freemium models to create a strong customer pipeline while monetizing premium-tier users effectively.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Subscription-Based Models&lt;/strong&gt;: Charging customers a recurring fee for access to AI features and products, providing a steady revenue stream. Subscription models allow businesses to build predictable revenue while fostering long-term customer relationships. Companies can structure subscriptions with multiple tiers, offering varied levels of AI functionalities, customer support, or additional integrations. Many AI-driven platforms use this approach to provide ongoing updates and improvements, ensuring continued customer value and retention.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By implementing the right monetization strategy, businesses can unlock the full potential of AI-driven features and products. Whether through direct sales, indirect revenue streams, or subscription-based models, companies can leverage AI to enhance their offerings and drive long-term growth. The key is to align monetization strategies with customer needs, ensuring both value delivery and sustainable revenue generation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pricing Models for AI
&lt;/h2&gt;

&lt;p&gt;Selecting the right AI pricing strategy is crucial to profitability. A well-structured pricing model ensures that businesses can maximize revenue while maintaining customer satisfaction. Companies must consider factors such as market demand, competitive positioning, and scalability when determining the most effective approach. Common models include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Usage-Based Pricing&lt;/strong&gt;: Charging per transaction, per query, or per processing cycle.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tiered Pricing&lt;/strong&gt;: Offering multiple subscription tiers, each unlocking different AI features.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Value-Based Pricing&lt;/strong&gt;: Pricing AI based on perceived value and user impact.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Choosing the right pricing model for AI solutions can significantly impact revenue and customer adoption. By aligning pricing with usage patterns, feature accessibility, or perceived value, businesses can optimize profitability while ensuring customer satisfaction. A flexible approach allows companies to adapt to market trends and evolving user needs, creating a sustainable and competitive pricing strategy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Operationalize Your AI Monetization Strategy
&lt;/h2&gt;

&lt;p&gt;To successfully monetize AI, businesses need the right infrastructure, compliance measures, and performance monitoring. Best practices include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Building a solid AI infrastructure&lt;/strong&gt;: Partnering with AI providers or developing in-house expertise.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Using AI pricing optimization tools&lt;/strong&gt;: Leveraging AI-powered insights to refine pricing strategies.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Focusing on customer feedback&lt;/strong&gt;: Implementing beta programs to assess user value.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Ensuring security and compliance&lt;/strong&gt;: Adhering to data protection regulations like GDPR and CCPA.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By focusing on these key operational elements, businesses can effectively implement their AI monetization strategy, ensuring that their AI capabilities are not only innovative but also profitable. A well-executed strategy involves a combination of robust infrastructure, strategic pricing, and a commitment to customer satisfaction.&lt;/p&gt;

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

&lt;p&gt;Successfully monetizing AI requires a blend of pricing strategy, value metrics, and ongoing customer engagement. Whether through direct monetization or indirect monetization, aligning AI functionalities with real-world user needs is key to driving revenue and maintaining a competitive edge.&lt;/p&gt;

&lt;p&gt;If you want to experience how an AI-powered API platform can transform your API product management, &lt;a href="https://www.moesif.com/wrap?onboard=true&amp;amp;utm_source=blog&amp;amp;utm_medium=bottom-cta&amp;amp;utm_content=DEVTO-Best-Practices-for-Monetizing-AI-Successfully" rel="noopener noreferrer"&gt;sign up for Moesif today for a free trial&lt;/a&gt;, no credit card required.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webmonetization</category>
      <category>revenuegrowth</category>
      <category>bestpractices</category>
    </item>
    <item>
      <title>Monitoring Cost and Consumption of AI APIs and Apps</title>
      <dc:creator>Moesif Staff</dc:creator>
      <pubDate>Thu, 20 Feb 2025 18:56:52 +0000</pubDate>
      <link>https://dev.to/moesif/monitoring-cost-and-consumption-of-ai-apis-and-apps-56gb</link>
      <guid>https://dev.to/moesif/monitoring-cost-and-consumption-of-ai-apis-and-apps-56gb</guid>
      <description>&lt;p&gt;The rise of AI has transformed how businesses operate, creating a surge in demand for AI-driven APIs, particularly those that leverage Large Language Models (LLMs). These APIs are at the heart of many modern applications, driving automation, customer interaction, and sophisticated data analysis. However, with this increased use comes a need for organizations to effectively monitor and manage the costs and consumption of these APIs. Understanding how different customers and applications interact with your APIs is crucial to maintaining profitability and ensuring efficient resource use.&lt;/p&gt;

&lt;p&gt;In this blog post, we’ll explore how Moesif can help organizations achieve full observability into their AI APIs. We’ll discuss common challenges like cost tracking, consumption monitoring, and how Moesif’s capabilities can simplify cost attribution, helping you stay in control of your AI-related expenditures. We'll also look into best practices for managing costs and ways to improve profitability using data-driven insights.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Challenge of Understanding Costs in AI APIs
&lt;/h2&gt;

&lt;p&gt;AI-powered APIs, especially those relying on LLMs such as OpenAI's models, introduce unique challenges when it comes to understanding costs. Unlike traditional APIs, the cost of LLM-based APIs can vary significantly depending on the nature of each request. Factors like the complexity of prompts, the volume of data processed, and compute intensity can all impact costs. This variability makes it challenging for organizations to maintain predictability and control over their operational expenses.&lt;/p&gt;

&lt;p&gt;For AI businesses to maintain a sustainable financial model, it’s essential to &lt;a href="https://www.moesif.com/blog/technical/api-development/Optimizing-Profits-Calculating-and-Reporting-COGS-for-Your-OpenAI-Powered-API/" rel="noopener noreferrer"&gt;calculate the Cost of Goods Sold (COGS) accurately&lt;/a&gt;. This requires comprehensive tracking of direct expenses, such as provider fees for AI models, as well as indirect costs, like infrastructure and server maintenance. Without accurate cost tracking, businesses risk running into budget overruns and profitability issues. Moesif offers a detailed view into these cost components by monitoring API interactions in real time, providing valuable insights that help ensure you are fully aware of what is driving your COGS.&lt;/p&gt;

&lt;p&gt;With Moesif’s capabilities, organizations can set up &lt;a href="https://www.moesif.com/features/api-dashboards" rel="noopener noreferrer"&gt;custom dashboards&lt;/a&gt; that provide detailed breakdowns of costs by different dimensions, such as request type, endpoint, or customer segment. This level of detail empowers finance and engineering teams to work together to optimize both cost efficiency and performance. By identifying where costs are highest and why, organizations can make informed decisions to improve their overall API strategy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Identifying High-Cost Customers
&lt;/h2&gt;

&lt;p&gt;One significant challenge that many companies face is identifying which customers are responsible for the bulk of their API costs. Different users interact with AI APIs in varying ways—some use straightforward, low-cost requests, while others may make highly complex or frequent requests that drive up costs considerably. This disparity in usage often means that a small percentage of customers contribute disproportionately to the overall API expenses.&lt;/p&gt;

&lt;p&gt;Moesif provides granular visibility into customer-specific API usage, enabling organizations to pinpoint which users are contributing most to operational expenses. With these insights, companies can make informed decisions about implementing tiered pricing models, optimizing customer usage, or even adjusting service levels to better align with their costs. By using Moesif, businesses can create user segmentation based on usage intensity and cost impact, allowing for more personalized communication and pricing adjustments.&lt;/p&gt;

&lt;p&gt;For example, a SaaS company offering an AI-based API could use Moesif to identify customers that frequently make high-cost API calls. By understanding these usage patterns, the company could introduce premium pricing plans tailored to customers who derive significant value from more intensive API use. Alternatively, they could work with these customers to optimize their API requests, potentially reducing their own costs while improving efficiency for the customer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monitoring Consumption for LLM APIs
&lt;/h2&gt;

&lt;p&gt;Large Language Models are powerful tools, but their cost structure can be challenging. The way customers use LLMs—such as making complex queries or frequent calls—can directly affect the overall expenses. In particular, queries that require significant computational power, such as those with extensive context or specialized responses, can increase the cost per request. Moesif enables real-time monitoring of LLM consumption, helping companies understand usage patterns that lead to higher costs.&lt;/p&gt;

&lt;p&gt;By analyzing customer interaction data, businesses can identify usage trends that may be leading to inefficiencies. For example, if a small subset of customers is responsible for an outsized portion of LLM costs, organizations can engage with those customers to optimize prompt usage or even shift them to a more cost-effective pricing tier. This level of insight allows companies to fine-tune their API strategy to manage costs without compromising customer satisfaction.&lt;/p&gt;

&lt;p&gt;Moesif also allows for proactive alerts and notifications. If a customer’s usage suddenly spikes, leading to higher-than-expected costs, teams can be alerted in real-time. This enables companies to take immediate action—such as reaching out to customers to understand the changes in their usage patterns, offering guidance on more efficient usage, or implementing rate limiting to prevent runaway costs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Breaking Down Costs by Tenant
&lt;/h2&gt;

&lt;p&gt;For companies that operate multi-tenant SaaS products, understanding the cost of supporting each tenant is essential. Moesif offers the ability to attribute costs accurately on a per-tenant basis, helping businesses understand how much each client is contributing to the overall expenditure. Tenant-level cost attribution provides crucial visibility that helps in financial planning and customer profitability analysis.&lt;/p&gt;

&lt;p&gt;This tenant-level visibility is especially valuable for SaaS providers who need to assess the financial impact of different tenants. By accurately attributing costs to each tenant, companies can make better decisions about pricing, resource allocation, and even customer support prioritization. For instance, if a particular tenant is driving significantly higher costs compared to others, the business can investigate why this is happening and whether it makes sense to adjust the pricing structure or impose usage limits.&lt;/p&gt;

&lt;p&gt;Additionally, having detailed insights into tenant-level costs allows businesses to better understand the value they provide to their customers. By correlating revenue generated from each tenant with their respective costs, companies can determine which customers are most profitable and which may need more attention to ensure they are a sustainable part of the business. This enables data-driven discussions with customers about the value they are receiving and potential ways to optimize their usage.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Use Moesif to Monitor and Manage Costs
&lt;/h2&gt;

&lt;p&gt;To achieve effective cost monitoring and control with Moesif, follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Set Up Real-Time Monitoring&lt;/strong&gt;: &lt;a href="https://www.moesif.com/features/api-monitoring" rel="noopener noreferrer"&gt;Moesif allows you to track every API request in real time&lt;/a&gt;. Begin by integrating Moesif into your API infrastructure. Once integrated, Moesif captures critical data such as request paths, response times, and payloads, which helps you understand your API's overall usage.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Create Custom Dashboards&lt;/strong&gt;: &lt;a href="https://www.moesif.com/features/api-dashboards" rel="noopener noreferrer"&gt;Use Moesif’s custom dashboards to visualize cost-related metrics&lt;/a&gt;. You can build dashboards that show detailed breakdowns by customer, endpoint, or type of request. This helps in identifying which parts of your API are contributing most to the costs and which users are driving up usage.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use Cost Analysis Metrics&lt;/strong&gt;: &lt;a href="https://www.moesif.com/features/product-catalog" rel="noopener noreferrer"&gt;Moesif provides the ability to assign costs to different API transactions&lt;/a&gt;. Set up metrics to track usage by customer, including the number of calls, data transferred, and the complexity of prompts sent to LLMs. This data helps in identifying the top customers contributing to costs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Set Alerts for Usage Spikes&lt;/strong&gt;: &lt;a href="https://www.moesif.com/features/api-monitoring" rel="noopener noreferrer"&gt;Establish alert triggers to notify you when a customer’s usage exceeds predefined thresholds&lt;/a&gt;. This helps in mitigating unexpected cost spikes before they impact your budget. Alerts can be set for different dimensions, such as high-frequency API calls or unusually large payloads.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Segment Customers by Usage&lt;/strong&gt;: &lt;a href="https://www.moesif.com/docs/api-analytics/segmentation/" rel="noopener noreferrer"&gt;Use Moesif’s segmentation tools to categorize customers based on their usage patterns&lt;/a&gt;. Identify heavy users who make complex or high-frequency requests and create segments for them. This will help tailor pricing models that better reflect the costs they incur.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Analyze Customer Behavior&lt;/strong&gt;: &lt;a href="https://www.moesif.com/features/behavioral-cohorts" rel="noopener noreferrer"&gt;Use the behavioral analysis tools in Moesif to understand how different customer segments interact with your API&lt;/a&gt;. Understanding the journey customers take and which endpoints they hit the most often allows you to optimize both user experience and cost efficiency.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Leverage Cost Attribution Features&lt;/strong&gt;: For multi-tenant SaaS platforms, &lt;a href="https://www.moesif.com/solutions/metered-api-billing" rel="noopener noreferrer"&gt;Moesif’s cost attribution features allow you to break down costs per tenant&lt;/a&gt;. This provides clarity on which tenants are using the most resources, enabling precise cost allocation and ensuring pricing structures are fair and reflective of usage.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Optimize Usage Patterns&lt;/strong&gt;: Once you have visibility into the cost drivers, work with customers to optimize their usage. This could involve helping them craft more efficient prompts, advising them on reducing request frequency, or recommending features that provide the most value at a lower cost.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Driving Profitability with Moesif
&lt;/h2&gt;

&lt;p&gt;Moesif doesn’t just help you monitor costs—it also helps optimize profitability. By combining usage data with cost insights, companies can better understand the relationship between customer behaviors and profitability. Moesif enables organizations to identify opportunities for upselling high-value features to customers who are already consuming significant resources or even to &lt;a href="https://www.moesif.com/features/api-governance-rules" rel="noopener noreferrer"&gt;introduce throttling mechanisms&lt;/a&gt; for customers whose usage exceeds acceptable cost limits.&lt;/p&gt;

&lt;p&gt;These actionable insights empower teams to proactively manage both customer experience and operational costs, ensuring that AI APIs remain both effective and profitable. Moesif's real-time monitoring, alert capabilities, and advanced analytics equip companies to make data-driven decisions that enhance efficiency and boost the bottom line. For example, identifying the most resource-intensive endpoints allows engineering teams to optimize those endpoints, potentially reducing the cost per request and improving the overall performance of the API.&lt;/p&gt;

&lt;p&gt;Moesif’s analytics enable teams to understand long-term trends in API usage and costs, which is vital for strategic planning. By visualizing how costs evolve over time and how different customers contribute to those trends, companies can adjust their growth strategies and anticipate future needs. Whether it's refining pricing models, reallocating infrastructure resources, or changing product offerings, Moesif's data-driven approach ensures that decisions are backed by comprehensive insights.&lt;/p&gt;

&lt;h2&gt;
  
  
  Best Practices for Cost Management
&lt;/h2&gt;

&lt;p&gt;To effectively manage costs associated with AI APIs, companies should adopt several best practices:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Segment Customers by Usage&lt;/strong&gt;: Use data to identify different segments of customers based on how they interact with your APIs. This can help tailor pricing and optimize resource use.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimize Prompts and Requests&lt;/strong&gt;: Work with customers to streamline their prompts and requests to minimize computational overhead while maintaining effectiveness.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set Up Alerts for Unusual Activity&lt;/strong&gt;: Leverage Moesif’s alert system to quickly respond to unexpected usage spikes that could lead to significant cost increases.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Regularly Review Cost and Usage Data&lt;/strong&gt;: Periodically assess your API usage and cost data to identify trends and make adjustments as needed. Moesif’s dashboards make this easy to visualize and analyze.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implement Tiered Pricing Models&lt;/strong&gt;: Consider &lt;a href="https://www.moesif.com/blog/api-analytics/product/Pricing-Strategies-for-APIs/" rel="noopener noreferrer"&gt;implementing pricing models&lt;/a&gt; that align more closely with the value delivered to customers and the costs incurred by their usage.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;AI has opened up remarkable opportunities for innovation, but it has also brought new challenges in managing the costs associated with API consumption. Moesif helps organizations overcome these challenges by offering comprehensive observability into the usage and cost of AI-driven APIs. From understanding LLM usage patterns to accurately attributing costs across tenants, Moesif provides the tools needed to turn complex cost structures into clear, actionable insights.&lt;/p&gt;

&lt;p&gt;By adopting best practices for cost management and leveraging Moesif’s advanced analytics and monitoring tools, businesses can ensure they stay ahead of the cost curve while continuing to deliver exceptional value through their AI APIs. If you're ready to take control of your API costs and get a clearer picture of your AI-powered applications, &lt;a href="https://www.moesif.com/wrap?onboard=true&amp;amp;utm_source=blog&amp;amp;utm_medium=bottom-cta&amp;amp;utm_content=DEVTO-Monitoring-Cost-and-Consumption-of-AI-APIs-and-Apps" rel="noopener noreferrer"&gt;start your 14-day free trial with Moesif today&lt;/a&gt;—no credit card required.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>moesif</category>
    </item>
    <item>
      <title>Debugging Production APIs with Postman and Moesif</title>
      <dc:creator>Moesif Staff</dc:creator>
      <pubDate>Wed, 19 Feb 2025 18:03:05 +0000</pubDate>
      <link>https://dev.to/moesif/debugging-production-apis-with-postman-and-moesif-39pl</link>
      <guid>https://dev.to/moesif/debugging-production-apis-with-postman-and-moesif-39pl</guid>
      <description>&lt;p&gt;Debugging APIs can be a challenge for any developer dealing with REST APIs. Trying to create an exact API request, especially for highly complex requests with large bodies and multiple headers, is essential but also tough to do. By using a tool like Postman to create a request for debugging and API testing purposes, you can easily replay an API request with the exact configuration of the original request. This can enable developers to reproduce the scenario when running API tests and debugging in a consistent manner.&lt;/p&gt;

&lt;p&gt;Moesif can also help to make the process of debugging and running API tests against your REST APIs easier as well. Since Moesif receives data around every aspect of a request, it makes it a great platform to export all of the details of a request so it can easily be replayed to assist with debugging. In Moesif, you can easily export all of your API call data into a Postman Collection. This helps developers to replicate the calls in Postman automatically by importing the generated Collection.&lt;/p&gt;

&lt;p&gt;Debugging best practices aim to ensure that the conditions in which you are debugging an error match exactly with the conditions that caused the error. By using Moesif’s export functionalities as part of your debugging and API testing method, you’re guaranteed that the API endpoint and debugger are receiving the same request data that caused the error.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exporting Events in Moesif
&lt;/h2&gt;

&lt;p&gt;To export calls from Moesif, first, navigate to the &lt;strong&gt;Live Event Log&lt;/strong&gt; screen. Click &lt;strong&gt;Create New&lt;/strong&gt; on the left navigation pane and select &lt;strong&gt;Live Event Log&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%2Fz5lft3o0dxu0zgefkjfm.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%2Fz5lft3o0dxu0zgefkjfm.png" alt="Moesifs Live Event Log" width="800" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can choose the calls you wish to export into the Postman Collection. You can easily select the desired calls by &lt;strong&gt;checking the boxes&lt;/strong&gt; next to them, and then export them by clicking on &lt;strong&gt;Run in Postman&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%2F2gi8nzgqo9q7esx0k8ry.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%2F2gi8nzgqo9q7esx0k8ry.png" alt="Selecting Requests" width="800" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;By exporting the calls to a Postman API collection, you will have all the necessary components at your disposal to recreate an API call. This includes the body, headers, parameters, and any other relevant elements.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After clicking the button labeled &lt;strong&gt;Run in Postman&lt;/strong&gt;, a modal window will pop up, giving you the option to download the collection. Simply click on &lt;strong&gt;Download Postman Collection&lt;/strong&gt; to acquire the collection file in a easy to read json format and save it on your local machine.&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%2Fi1hymkcxqjc38d0yxyrm.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%2Fi1hymkcxqjc38d0yxyrm.png" alt="Downloading a Postman collection in Moesif" width="660" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Postman API Collection will be downloaded and ready to load into Postman. Let’s check out how to do that!&lt;/p&gt;

&lt;h2&gt;
  
  
  Importing the Collection in Postman
&lt;/h2&gt;

&lt;p&gt;Open Postman and click the &lt;strong&gt;Collections&lt;/strong&gt; tab on the left side of screen. Click the &lt;strong&gt;Import&lt;/strong&gt; button on the top left.&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%2F9cv6puryt98037o86pfz.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%2F9cv6puryt98037o86pfz.png" alt="Import collection into Postman" width="800" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After that, a modal will appear where you can either select the Postman Collection file or drag-and-drop it onto the modal to import it.&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%2F5zvcmk4dwijoknqgj802.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%2F5zvcmk4dwijoknqgj802.png" alt="Postman import file" width="800" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The collection will be displayed in the &lt;strong&gt;Collections&lt;/strong&gt; pane in Postman.&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%2Fj0jg573wl32fwlkfr9p0.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%2Fj0jg573wl32fwlkfr9p0.png" alt="Postman Collection List" width="800" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Replaying Requests and Debugging
&lt;/h2&gt;

&lt;p&gt;Choose one of the requests to replay and all the details of the HTTP request will be shown, including the parameters, headers, and body.&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%2F041zyuloozm9g39bgop1.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%2F041zyuloozm9g39bgop1.png" alt="Postman API list view" width="800" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click the blue &lt;strong&gt;Send&lt;/strong&gt; button located beside the URL to send a Postman API call which is an exact copy of the web API request you are trying to debug to the desired endpoint. By doing this, your debugger will be loaded with the same data as the error call you are currently debugging since it has been loaded from the exported Postman API Collection.&lt;/p&gt;

&lt;h2&gt;
  
  
  Experience It for Yourself
&lt;/h2&gt;

&lt;p&gt;The next time you encounter an issue while debugging or conducting API tests with your REST API , you can make use of Moesif to easily replicate the HTTP requests that led to the error. No need to worry about missing details by manually inputting the HTTP request into Postman. Simply export the request from Moesif and replay it through Postman to debug your API in the exact same conditions that caused the issue in the first place. Just choose the requests that you need, export them, and start debugging. By doing so, you’ll be able to hit your debugger breakpoint with the same data included in the original request. Debugging REST API errors should be a breeze, and with Postman and Moesif, it definitely is!&lt;/p&gt;

&lt;p&gt;If you want to enhance your debugging and API testing capabilities, Moesif is the way to go. It lets you effortlessly replicate the HTTP request that caused an error in your REST API code, without any risk of omitting important details. You can then export the requests and replay them in Postman to debug your API under the exact same conditions that led to the issue. With &lt;a href="https://www.moesif.com/signup?utm_campaign=Int-site&amp;amp;utm_source=blog&amp;amp;utm_medium=body-cta&amp;amp;utm_term=devto-debugging-production-with-postman" rel="noopener noreferrer"&gt;Moesif&lt;/a&gt;, debugging REST API errors becomes a breeze.&lt;/p&gt;

</description>
      <category>api</category>
      <category>postman</category>
      <category>moesif</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
