<?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: Vishal Anand</title>
    <description>The latest articles on DEV Community by Vishal Anand (@vishalanandl177).</description>
    <link>https://dev.to/vishalanandl177</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F367795%2F41ea9e34-9202-44d1-b668-25d252312722.jpeg</url>
      <title>DEV Community: Vishal Anand</title>
      <link>https://dev.to/vishalanandl177</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vishalanandl177"/>
    <language>en</language>
    <item>
      <title>Adding Production-Safe API Logging to Django REST Framework</title>
      <dc:creator>Vishal Anand</dc:creator>
      <pubDate>Mon, 06 Jul 2026 18:05:35 +0000</pubDate>
      <link>https://dev.to/vishalanandl177/adding-production-safe-api-logging-to-django-rest-framework-8gi</link>
      <guid>https://dev.to/vishalanandl177/adding-production-safe-api-logging-to-django-rest-framework-8gi</guid>
      <description>&lt;p&gt;When a Django REST Framework API starts getting used in production, one of the first debugging problems is visibility.&lt;/p&gt;

&lt;p&gt;A user reports:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“The API failed.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But from the backend side, we often need more context:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which endpoint was called?&lt;/li&gt;
&lt;li&gt;What was the HTTP method?&lt;/li&gt;
&lt;li&gt;What status code was returned?&lt;/li&gt;
&lt;li&gt;How long did the request take?&lt;/li&gt;
&lt;li&gt;Was the request body valid?&lt;/li&gt;
&lt;li&gt;Did the response fail because of validation, permissions, database latency, or something else?&lt;/li&gt;
&lt;li&gt;Can we debug this without exposing passwords, tokens, or sensitive payloads?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Many teams solve this by writing custom middleware.&lt;/p&gt;

&lt;p&gt;That works at first, but it can become risky over time.&lt;/p&gt;

&lt;p&gt;Custom API logging often starts small:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then it grows into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;storing logs in the database&lt;/li&gt;
&lt;li&gt;masking sensitive values&lt;/li&gt;
&lt;li&gt;handling large request/response bodies&lt;/li&gt;
&lt;li&gt;tracking slow APIs&lt;/li&gt;
&lt;li&gt;searching logs from Django admin&lt;/li&gt;
&lt;li&gt;avoiding extra latency in the request path&lt;/li&gt;
&lt;li&gt;supporting async deployments&lt;/li&gt;
&lt;li&gt;adding request correlation or trace IDs&lt;/li&gt;
&lt;li&gt;avoiding accidental logging of tokens, passwords, cookies, or API keys&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At that point, API logging is no longer “just middleware”. It becomes part of production observability.&lt;/p&gt;

&lt;p&gt;This is the problem I wanted to solve with &lt;strong&gt;DRF API Logger&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Disclosure: I maintain this open-source package. I am sharing it here because I think the problem is common in Django REST Framework projects, and I would also like feedback from other Django developers.&lt;/p&gt;

&lt;h2&gt;
  
  
  What DRF API Logger does
&lt;/h2&gt;

&lt;p&gt;DRF API Logger is an open-source package for Django REST Framework projects that captures API request and response information.&lt;/p&gt;

&lt;p&gt;It can log useful debugging information such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API URL&lt;/li&gt;
&lt;li&gt;HTTP method&lt;/li&gt;
&lt;li&gt;request headers&lt;/li&gt;
&lt;li&gt;request body&lt;/li&gt;
&lt;li&gt;response body&lt;/li&gt;
&lt;li&gt;status code&lt;/li&gt;
&lt;li&gt;client IP address&lt;/li&gt;
&lt;li&gt;API execution time&lt;/li&gt;
&lt;li&gt;optional request tracing information&lt;/li&gt;
&lt;li&gt;slow API indicators&lt;/li&gt;
&lt;li&gt;optional profiling information&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is not to replace every observability tool.&lt;/p&gt;

&lt;p&gt;It is mainly useful when you want structured API-level logging inside a Django/DRF project without building and maintaining custom middleware from scratch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not simply write custom middleware?
&lt;/h2&gt;

&lt;p&gt;You can write your own middleware, and for small projects that may be enough.&lt;/p&gt;

&lt;p&gt;But production API logging has some common traps.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Sensitive data exposure
&lt;/h3&gt;

&lt;p&gt;This is the biggest issue.&lt;/p&gt;

&lt;p&gt;Logging the full request body may accidentally store:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;passwords&lt;/li&gt;
&lt;li&gt;access tokens&lt;/li&gt;
&lt;li&gt;refresh tokens&lt;/li&gt;
&lt;li&gt;API keys&lt;/li&gt;
&lt;li&gt;session IDs&lt;/li&gt;
&lt;li&gt;cookies&lt;/li&gt;
&lt;li&gt;authorization headers&lt;/li&gt;
&lt;li&gt;personal user data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That makes logs dangerous.&lt;/p&gt;

&lt;p&gt;Good API logging should support masking and exclusion rules from the beginning.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;DRF_API_LOGGER_EXCLUDE_KEYS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;password&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;token&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;access&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;refresh&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;secret&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;api_key&lt;/span&gt;&lt;span class="sh"&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;Even with masking, teams should still review what they log and decide what is acceptable for their own security, privacy, and compliance requirements.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Performance overhead
&lt;/h3&gt;

&lt;p&gt;A simple custom logger may write to the database directly inside the request/response cycle.&lt;/p&gt;

&lt;p&gt;That means every API request waits for logging work to finish.&lt;/p&gt;

&lt;p&gt;For low traffic, this may be acceptable. For production traffic, this can add unnecessary latency.&lt;/p&gt;

&lt;p&gt;A better pattern is to keep request-path work small and move heavier writes out of the main request flow where possible.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Large payloads
&lt;/h3&gt;

&lt;p&gt;Some APIs return large JSON responses.&lt;/p&gt;

&lt;p&gt;If logs store everything without limits, the logging table can grow quickly and become expensive to query.&lt;/p&gt;

&lt;p&gt;A production logging setup should support body-size limits.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;DRF_API_LOGGER_MAX_REQUEST_BODY_SIZE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;32768&lt;/span&gt;
&lt;span class="n"&gt;DRF_API_LOGGER_MAX_RESPONSE_BODY_SIZE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;65536&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Search and debugging experience
&lt;/h3&gt;

&lt;p&gt;Storing logs is only useful if developers can find the right records later.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;show all 500 responses from the last hour&lt;/li&gt;
&lt;li&gt;search by URL&lt;/li&gt;
&lt;li&gt;filter by method&lt;/li&gt;
&lt;li&gt;find slow APIs&lt;/li&gt;
&lt;li&gt;inspect a specific failed request&lt;/li&gt;
&lt;li&gt;compare status codes&lt;/li&gt;
&lt;li&gt;check execution time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where Django admin visibility becomes useful for many teams.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic installation
&lt;/h2&gt;

&lt;p&gt;Install the package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;drf-api-logger
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add it to &lt;code&gt;INSTALLED_APPS&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;# ...
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;drf_api_logger&lt;/span&gt;&lt;span class="sh"&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;Add the middleware:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;MIDDLEWARE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;# ...
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;drf_api_logger.middleware.api_logger_middleware.APILoggerMiddleware&lt;/span&gt;&lt;span class="sh"&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;Enable database logging:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;DRF_API_LOGGER_DATABASE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run migrations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python manage.py migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After this, DRF API logs can be captured and viewed from Django admin.&lt;/p&gt;

&lt;h2&gt;
  
  
  A more production-aware configuration
&lt;/h2&gt;

&lt;p&gt;For production-like environments, I would avoid enabling full logging blindly.&lt;/p&gt;

&lt;p&gt;A safer starting point is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;DRF_API_LOGGER_DATABASE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

&lt;span class="n"&gt;DRF_API_LOGGER_EXCLUDE_KEYS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;password&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;token&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;access&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;refresh&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;secret&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;api_key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cookie&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;set-cookie&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;DRF_API_LOGGER_MAX_REQUEST_BODY_SIZE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;32768&lt;/span&gt;
&lt;span class="n"&gt;DRF_API_LOGGER_MAX_RESPONSE_BODY_SIZE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;65536&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This keeps the setup practical while reducing some common risks.&lt;/p&gt;

&lt;p&gt;You should still review:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;which endpoints should be logged&lt;/li&gt;
&lt;li&gt;which fields should always be masked&lt;/li&gt;
&lt;li&gt;how long logs should be retained&lt;/li&gt;
&lt;li&gt;whether request/response bodies should be stored in your environment&lt;/li&gt;
&lt;li&gt;whether logs contain personal or regulated data&lt;/li&gt;
&lt;li&gt;whether logs should go to a separate database or storage backend&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Using it for slow API investigation
&lt;/h2&gt;

&lt;p&gt;One common use case is finding slow DRF endpoints.&lt;/p&gt;

&lt;p&gt;For example, you may want to flag APIs slower than a specific threshold:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;DRF_API_LOGGER_SLOW_API_ABOVE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also enable profiling when you need deeper investigation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;DRF_API_LOGGER_ENABLE_PROFILING&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This can help identify whether slowness is more likely coming from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SQL queries&lt;/li&gt;
&lt;li&gt;too many repeated queries&lt;/li&gt;
&lt;li&gt;middleware overhead&lt;/li&gt;
&lt;li&gt;view/business logic&lt;/li&gt;
&lt;li&gt;serialization cost&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is useful when an endpoint “feels slow” but the team does not yet know where the time is going.&lt;/p&gt;

&lt;h2&gt;
  
  
  Database logging vs signal-based logging
&lt;/h2&gt;

&lt;p&gt;Not every team wants to store API logs in the default database.&lt;/p&gt;

&lt;p&gt;Some teams may want to send API log data somewhere else:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a file&lt;/li&gt;
&lt;li&gt;an analytics pipeline&lt;/li&gt;
&lt;li&gt;a monitoring system&lt;/li&gt;
&lt;li&gt;a separate database&lt;/li&gt;
&lt;li&gt;a queue&lt;/li&gt;
&lt;li&gt;a custom internal tool&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For that, signal-based logging can be useful.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;DRF_API_LOGGER_SIGNAL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then a listener can handle the log event:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;drf_api_logger&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;API_LOGGER_SIGNAL&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send_to_internal_observability_tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Example only.
&lt;/span&gt;    &lt;span class="c1"&gt;# Be careful not to export sensitive request/response bodies.
&lt;/span&gt;    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;api&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;api&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;method&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;method&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status_code&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status_code&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;execution_time&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;execution_time&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;


&lt;span class="n"&gt;API_LOGGER_SIGNAL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;listen&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;send_to_internal_observability_tool&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives more flexibility if the default database is not the right place for logs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security and privacy notes
&lt;/h2&gt;

&lt;p&gt;API logs can be extremely helpful, but they can also become a liability.&lt;/p&gt;

&lt;p&gt;Before enabling request/response logging in production, I recommend reviewing these questions:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Are we logging secrets?
&lt;/h3&gt;

&lt;p&gt;Avoid storing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;passwords&lt;/li&gt;
&lt;li&gt;tokens&lt;/li&gt;
&lt;li&gt;API keys&lt;/li&gt;
&lt;li&gt;cookies&lt;/li&gt;
&lt;li&gt;session IDs&lt;/li&gt;
&lt;li&gt;authorization headers&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Are we logging personal data?
&lt;/h3&gt;

&lt;p&gt;Depending on your application, request and response bodies may contain personal information.&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;names&lt;/li&gt;
&lt;li&gt;phone numbers&lt;/li&gt;
&lt;li&gt;email addresses&lt;/li&gt;
&lt;li&gt;addresses&lt;/li&gt;
&lt;li&gt;payment-related information&lt;/li&gt;
&lt;li&gt;health-related information&lt;/li&gt;
&lt;li&gt;user documents&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do not treat API logs as harmless debugging data.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Do we need full bodies?
&lt;/h3&gt;

&lt;p&gt;For many APIs, logging metadata is enough:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;URL&lt;/li&gt;
&lt;li&gt;method&lt;/li&gt;
&lt;li&gt;status code&lt;/li&gt;
&lt;li&gt;execution time&lt;/li&gt;
&lt;li&gt;client IP&lt;/li&gt;
&lt;li&gt;trace ID&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Full request/response bodies should be enabled carefully.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. What is the retention policy?
&lt;/h3&gt;

&lt;p&gt;Logs should not live forever by default.&lt;/p&gt;

&lt;p&gt;Teams should decide how long API logs are useful and when they should be deleted or archived.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Who can access the logs?
&lt;/h3&gt;

&lt;p&gt;If logs are visible in Django admin, make sure admin access is properly restricted.&lt;/p&gt;

&lt;p&gt;API logs may reveal internal system behavior and user data.&lt;/p&gt;

&lt;h2&gt;
  
  
  When I would use this package
&lt;/h2&gt;

&lt;p&gt;I would consider using DRF API Logger when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the project uses Django REST Framework&lt;/li&gt;
&lt;li&gt;the team needs request/response visibility&lt;/li&gt;
&lt;li&gt;developers are currently debugging production issues manually&lt;/li&gt;
&lt;li&gt;custom middleware is growing too complex&lt;/li&gt;
&lt;li&gt;slow API investigation is needed&lt;/li&gt;
&lt;li&gt;Django admin visibility is useful&lt;/li&gt;
&lt;li&gt;sensitive data masking and payload limits are required&lt;/li&gt;
&lt;li&gt;the team wants a package instead of maintaining logging middleware internally&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When I would not use it
&lt;/h2&gt;

&lt;p&gt;I would not enable full API body logging blindly in every project.&lt;/p&gt;

&lt;p&gt;I would be careful if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the application handles highly sensitive data&lt;/li&gt;
&lt;li&gt;compliance requirements are strict&lt;/li&gt;
&lt;li&gt;the team does not have a retention policy&lt;/li&gt;
&lt;li&gt;admin access is not well controlled&lt;/li&gt;
&lt;li&gt;the database is already under heavy write load&lt;/li&gt;
&lt;li&gt;only high-level metrics are needed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In those cases, metadata-only logging, signal-based logging, OpenTelemetry, APM tools, or custom policies may be more appropriate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Minimal example
&lt;/h2&gt;

&lt;p&gt;Here is a compact setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;# ...
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;drf_api_logger&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;MIDDLEWARE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;# ...
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;drf_api_logger.middleware.api_logger_middleware.APILoggerMiddleware&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;DRF_API_LOGGER_DATABASE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

&lt;span class="n"&gt;DRF_API_LOGGER_EXCLUDE_KEYS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;password&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;token&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;access&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;refresh&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;secret&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;api_key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;DRF_API_LOGGER_MAX_REQUEST_BODY_SIZE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;32768&lt;/span&gt;
&lt;span class="n"&gt;DRF_API_LOGGER_MAX_RESPONSE_BODY_SIZE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;65536&lt;/span&gt;

&lt;span class="n"&gt;DRF_API_LOGGER_SLOW_API_ABOVE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python manage.py migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Project links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/vishalanandl177/DRF-API-Logger" rel="noopener noreferrer"&gt;https://github.com/vishalanandl177/DRF-API-Logger&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PyPI: &lt;a href="https://pypi.org/project/drf-api-logger/" rel="noopener noreferrer"&gt;https://pypi.org/project/drf-api-logger/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Feedback request
&lt;/h2&gt;

&lt;p&gt;I would appreciate feedback from Django and DRF developers on a few areas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What do you expect from API logging in production?&lt;/li&gt;
&lt;li&gt;Do you prefer database logging, signals, OpenTelemetry, or another storage backend?&lt;/li&gt;
&lt;li&gt;What masking rules should be enabled by default?&lt;/li&gt;
&lt;li&gt;What would make the admin debugging experience more useful?&lt;/li&gt;
&lt;li&gt;What concerns would stop you from using request/response logging?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I am especially interested in feedback around security, privacy, performance, and real production debugging workflows.&lt;/p&gt;

&lt;p&gt;Thanks for reading.&lt;/p&gt;

</description>
      <category>drfapilogger</category>
      <category>django</category>
      <category>drf</category>
      <category>logging</category>
    </item>
    <item>
      <title>MySQL Bulk Insert taking long time</title>
      <dc:creator>Vishal Anand</dc:creator>
      <pubDate>Tue, 09 Jun 2020 13:51:39 +0000</pubDate>
      <link>https://dev.to/vishalanandl177/mysql-bulk-insert-taking-long-time-1omk</link>
      <guid>https://dev.to/vishalanandl177/mysql-bulk-insert-taking-long-time-1omk</guid>
      <description>&lt;p&gt;I'm using python, using MySQL connector. I'm having nearly 67 Million (14GB) entries in a table. When I do a bulk insert of 2K data each time, it is taking very long to insert.&lt;/p&gt;

&lt;p&gt;Inserted 2000 rows in 23 Seconds&lt;br&gt;
Inserted 2000 rows in 25 Seconds&lt;br&gt;
Inserted 2000 rows in 29 Seconds&lt;br&gt;
Inserted 2000 rows in 28 Seconds&lt;br&gt;
For another table (having less data), insertion speed is fine(2-4 seconds).&lt;/p&gt;

&lt;p&gt;After using the transaction:&lt;/p&gt;

&lt;p&gt;Inserted 2000 rows in 21 Seconds&lt;br&gt;
Inserted 2000 rows in 20 Seconds&lt;br&gt;
Inserted 2000 rows in 20 Seconds&lt;br&gt;
Inserted 2000 rows in 18 Seconds&lt;br&gt;
How can I improve the speed?&lt;/p&gt;

&lt;p&gt;I'm using AWS RDS, Aurora MySQL version 5.7.12 (db.t3.medium) having CPU usage 4% to 8%. My objective is to insert around 50K data into a table. This table is currently having nearly 67 Million (14GB) data already. Data must need to be inserted ASAP. This almost real-time data is very important for the client. The table is having 18 columns: id(PK auto-increment), customer, serial_number, batch, data, and some others. Indexes are on (customer,serial_number) - To make the combination unique, batch - For searching, data(unique). All are by default BTREE indexed. This insertion should need to take less than 1 minute for 50K. But currently taking around 15 minutes. I've tried inserting on an empty table. It is inserting 50K data just in 5-7 seconds. As you increase the number of entries in the table, the insertion process time is increasing.&lt;/p&gt;

&lt;p&gt;Is upgrading MySQL version is going to speed-up the insertion process anyhow? Is it the last option to split or partitioning the table? I cannot consolidate the data because each data is important, specially the last 2 years of data. Please help.&lt;/p&gt;

&lt;p&gt;My table schema is already having some default values in 8 columns and these data are never going to update later. There are not many Read/Write operations are going on. Almost 2 or in some cases 3 selects per second as per RDS monitor shows.&lt;/p&gt;

</description>
      <category>python</category>
      <category>database</category>
      <category>sql</category>
      <category>aws</category>
    </item>
    <item>
      <title>How to write cron jobs on AWS EC2 instance</title>
      <dc:creator>Vishal Anand</dc:creator>
      <pubDate>Thu, 16 Apr 2020 07:22:30 +0000</pubDate>
      <link>https://dev.to/vishalanandl177/how-to-write-cron-jobs-on-aws-ec2-instance-mf4</link>
      <guid>https://dev.to/vishalanandl177/how-to-write-cron-jobs-on-aws-ec2-instance-mf4</guid>
      <description>&lt;p&gt;Cron is a time-based job scheduler run on the server in the Unix-like operating system.&lt;br&gt;
To perform such action we write cron expression made of five fields, followed by a shell command to execute.&lt;/p&gt;

&lt;p&gt;First, we have to log in to AWS EC2 instance using CLI (Command Line Interface).&lt;br&gt;
For log in, type:&lt;br&gt;
ssh -i &amp;lt;.pem file&amp;gt; username@ip_address&lt;br&gt;
After successfully log in, type: &lt;br&gt;
crontab -e&lt;br&gt;
then select any editor from the list (preferred nano).&lt;br&gt;
 Type cron command. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;* * * * * php /var/www/html/file/name.php
Now save the changes. If you are using nano editor type Ctrl + x and Select Y and then press Enter.
To list out all the running cron type:
crontab -l&lt;/li&gt;
&lt;li&gt;is used for every minute, every hour, etc. Here ”php” is shell command followed by file location of php script, separated by white space.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to run nodejs script then type:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;* * * * * node /var/www/html/nodejs/file/name.js
Each from five stars represents a job:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How to write CRON jobs on AWS EC2 instance&lt;/p&gt;

&lt;p&gt;Allowed special characters are:&lt;/p&gt;

&lt;p&gt;Comma (,) – Commas are used to separate the item list.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;Cron to run at minute 1 and 10 every hour &lt;br&gt;
1,10 * * * * php /var/www/html/file/name.php&lt;br&gt;
Cron to run at mid-night and mid-day &lt;br&gt;
0 0,12 * * * php /var/www/html/file/name.php&lt;br&gt;
Hyphen (-) – Hyphen defines range.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;Cron to run at every minute from 1 minute through 10 minute, every hour&lt;br&gt;
0-10 * * * * php /var/www/html/file/name.php&lt;br&gt;
Cron to run at minute 0 past every hour from 6 AM through 6 PM &lt;br&gt;
0 6-18 * * * php /var/www/html/file/name.php&lt;br&gt;
Slash (/) – Slash defines step values.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;Cron to run every 5th minute &lt;br&gt;
*/5 * * * * php /var/www/html/file/name.php&lt;br&gt;
Cron to run at minute 0 past every 6th hour &lt;br&gt;
0 */6 * * * php /var/www/html/file/name.php&lt;br&gt;
Sleep cron:&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;Cron to run every minute after sleep of 30 seconds&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;* * * * * sleep 30; php /var/www/html/file/name.php&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more examples visit: &lt;a href="https://coderssecret.com/how-to-write-cron-jobs-on-aws-ec2-instance/"&gt;https://coderssecret.com/how-to-write-cron-jobs-on-aws-ec2-instance/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cron</category>
      <category>ec2</category>
    </item>
  </channel>
</rss>
