<?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: Mukul Sharma</title>
    <description>The latest articles on DEV Community by Mukul Sharma (@mukulsharma).</description>
    <link>https://dev.to/mukulsharma</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%2F1599906%2Fa0a214fd-2960-4aa2-8805-05c887403f7a.png</url>
      <title>DEV Community: Mukul Sharma</title>
      <link>https://dev.to/mukulsharma</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mukulsharma"/>
    <language>en</language>
    <item>
      <title>Blocking FastAPI Access Logs</title>
      <dc:creator>Mukul Sharma</dc:creator>
      <pubDate>Sun, 14 Jul 2024 03:55:08 +0000</pubDate>
      <link>https://dev.to/mukulsharma/taming-fastapi-access-logs-3idi</link>
      <guid>https://dev.to/mukulsharma/taming-fastapi-access-logs-3idi</guid>
      <description>&lt;p&gt;Have you ever found your FastAPI deployment cluttered with unnecessary access logs? These logs can create more noise than value, obscuring important information. Let's explore a neat trick to selectively block these access logs in FastAPI.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fjsa7soxyvzg4k84pdzek.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fjsa7soxyvzg4k84pdzek.png" alt="The Problem"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Access logs can quickly overwhelm your console, making it difficult to spot critical information.&lt;/p&gt;




&lt;h2&gt;
  
  
  No B.S. Solution
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExamN3YnNpb3NqNzA0czJ0NjVkMWFqODVjZG95enY0Y253aXBxeGNobiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/Dd7eqfJIDTnEmSVRGn/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExamN3YnNpb3NqNzA0czJ0NjVkMWFqODVjZG95enY0Y253aXBxeGNobiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/Dd7eqfJIDTnEmSVRGn/giphy.gif" alt="No Drama, No BS"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;

&lt;span class="c1"&gt;# main.py
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;

&lt;span class="n"&gt;block_endpoints&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;/endpoint1&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;/endpoint2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LogFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Filter&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;block_endpoints&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

&lt;span class="n"&gt;uvicorn_logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;uvicorn.access&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;uvicorn_logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LogFilter&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  How It Works
&lt;/h3&gt;

&lt;p&gt;We create a &lt;code&gt;LogFilter&lt;/code&gt; class that inherits from &lt;code&gt;logging.Filter&lt;/code&gt;.&lt;br&gt;
The filter method checks if the log record corresponds to one of our blocked endpoints.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If the endpoint is in our &lt;code&gt;block_endpoints&lt;/code&gt; list, we return 
&lt;strong&gt;False&lt;/strong&gt;, preventing the log from being processed.&lt;/li&gt;
&lt;li&gt;By default we return &lt;strong&gt;True&lt;/strong&gt; to log as usual.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We apply this filter to Uvicorn's access logger, which FastAPI uses under the hood.&lt;/p&gt;


&lt;h3&gt;
  
  
  Going Deep
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fee7r7tpa4whjjbwmhpig.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fee7r7tpa4whjjbwmhpig.jpg" alt="The Deep from The Boys"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When working with Python's logging module, each log entry is represented by a &lt;code&gt;LogRecord&lt;/code&gt; object. In our &lt;code&gt;LogFilter&lt;/code&gt; class, the &lt;code&gt;record&lt;/code&gt; parameter is an instance of this &lt;code&gt;LogRecord&lt;/code&gt; class.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;args&lt;/code&gt; attribute of a &lt;code&gt;LogRecord&lt;/code&gt; contains a tuple of arguments which are merged into the log message. In the context of Uvicorn's access logs, these arguments hold valuable information about each request. Here's a breakdown of what each argument typically represents:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;

&lt;span class="c1"&gt;# Typical structure of record.args for Uvicorn access logs
&lt;/span&gt;&lt;span class="n"&gt;remote_address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# IP address of the client
&lt;/span&gt;&lt;span class="n"&gt;request_method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# HTTP method (GET, POST, etc.)
&lt;/span&gt;&lt;span class="n"&gt;query_string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;    &lt;span class="c1"&gt;# Full path including query parameters
&lt;/span&gt;&lt;span class="n"&gt;html_version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;    &lt;span class="c1"&gt;# HTTP version used
&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;     &lt;span class="c1"&gt;# HTTP status code of the response
&lt;/span&gt;

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

&lt;/div&gt;

&lt;p&gt;Understanding this structure allows us to create more sophisticated filters. For example, we could filter logs based on status codes, specific IP addresses, or HTTP methods, not just endpoint paths.&lt;/p&gt;




&lt;h3&gt;
  
  
  Gotchas and Tips
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;This method works with Uvicorn's default logging setup. If you've customized your logging configuration, you might need to adjust the logger name.&lt;/li&gt;
&lt;li&gt;At times you might have a separate file for logging config such as &lt;code&gt;logger.py&lt;/code&gt;. You may define the class &lt;strong&gt;LogFilter&lt;/strong&gt; there but make sure to apply &lt;code&gt;.addFilter&lt;/code&gt; in &lt;code&gt;main.py&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Remember that completely blocking logs for certain endpoints might make debugging more challenging. Use this technique judiciously.&lt;/p&gt;

&lt;p&gt;As &lt;strong&gt;thank you&lt;/strong&gt; for making it to the end of this post, here is a trick I use for maximum benefit.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;

&lt;span class="c1"&gt;# main.py
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;

&lt;span class="n"&gt;block_endpoints&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;/endpoint1&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;/endpoint2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LogFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Filter&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;block_endpoints&lt;/span&gt; 
                &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;200&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

&lt;span class="n"&gt;uvicorn_logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;uvicorn.access&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;uvicorn_logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LogFilter&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;This will only block the request if the status code is &lt;em&gt;200&lt;/em&gt;. This is super helpful when blocking &lt;code&gt;INFO&lt;/code&gt; endpoints where you only need to be informed if an unexpected status code was returned.&lt;/p&gt;




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

&lt;p&gt;By implementing this simple logging filter, you can significantly reduce noise in your FastAPI application logs. This allows you to focus on the information that truly matters, making your debugging and monitoring processes more efficient.&lt;/p&gt;

&lt;h4&gt;
  
  
  What to do next?
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Feel free to ask questions and share your experience in the comments below!&lt;/li&gt;
&lt;li&gt;For further reading, check &lt;a href="https://github.com/encode/starlette/issues/864" rel="noopener noreferrer"&gt;this&lt;/a&gt; GitHub discussion.&lt;/li&gt;
&lt;li&gt;Check out my LinkedIn &lt;a href="https://www.linkedin.com/in/mukuliskul" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>fastapi</category>
      <category>python</category>
      <category>filter</category>
      <category>logs</category>
    </item>
    <item>
      <title>Handling AWS WAF Capacity Limits with Terraform</title>
      <dc:creator>Mukul Sharma</dc:creator>
      <pubDate>Sun, 09 Jun 2024 18:28:02 +0000</pubDate>
      <link>https://dev.to/mukulsharma/handling-aws-waf-capacity-limits-with-terraform-1741</link>
      <guid>https://dev.to/mukulsharma/handling-aws-waf-capacity-limits-with-terraform-1741</guid>
      <description>&lt;p&gt;When managing AWS WAF resources using Terraform, one common issue is exceeding the Web ACL Capacity Units (WCUs) limit, which can lead to deployment failures. This blog post will guide you through understanding WCUs, checking capacity using AWS CLI, and integrating this process into your Terraform workflow to ensure smooth deployments.&lt;/p&gt;

&lt;h4&gt;
  
  
  Understanding WCUs in AWS WAF
&lt;/h4&gt;

&lt;p&gt;AWS WAF uses Web ACL Capacity Units (WCUs) to measure the resources required to run rules, rule groups, and Web ACLs. Each rule type has a different capacity requirement based on its complexity and processing needs. The capacity limits help AWS manage the performance and cost of running WAF rules efficiently.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Simple Rules&lt;/strong&gt;: Require fewer WCUs (e.g., size constraint rules).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complex Rules&lt;/strong&gt;: Require more WCUs (e.g., regex pattern sets).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For detailed WCU calculations, refer to the &lt;a href="https://docs.aws.amazon.com/waf/latest/developerguide/aws-waf-capacity-units.html"&gt;AWS WAF documentation&lt;/a&gt; &lt;a href="https://docs.aws.amazon.com/waf/latest/developerguide/aws-waf-capacity-units.html"&gt;oai_citation:1,AWS WAF web ACL capacity units (WCUs) - AWS WAF, AWS Firewall Manager, and AWS Shield Advanced&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Common Error
&lt;/h4&gt;

&lt;p&gt;When you exceed the WCU limits, you may encounter the following error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WAFInvalidParameterException: Error reason: You exceeded the capacity limit for a rule group or web ACL.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Checking WCU Requirements with AWS CLI
&lt;/h4&gt;

&lt;p&gt;Terraform lacks built-in functionality to check WCUs before applying configurations. However, AWS CLI provides a &lt;code&gt;check-capacity&lt;/code&gt; command to verify the WCU requirements. Here’s how you can use it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Define WAF Rules in JSON&lt;/strong&gt;:
Create a JSON file (&lt;code&gt;rules.json&lt;/code&gt;) with the rules you want to include:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&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;"Rules"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"Name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Rule1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"Priority"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&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;"Statement"&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="nl"&gt;"ByteMatchStatement"&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="nl"&gt;"SearchString"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"BadBot"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
             &lt;/span&gt;&lt;span class="nl"&gt;"FieldToMatch"&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="nl"&gt;"UriPath"&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="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
             &lt;/span&gt;&lt;span class="nl"&gt;"TextTransformations"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="nl"&gt;"Priority"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="nl"&gt;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NONE"&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="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="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"Action"&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="nl"&gt;"Block"&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="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"VisibilityConfig"&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="nl"&gt;"SampledRequestsEnabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="nl"&gt;"CloudWatchMetricsEnabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="nl"&gt;"MetricName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Rule1Metric"&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="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="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Run the &lt;code&gt;check-capacity&lt;/code&gt; Command&lt;/strong&gt;:
Use the AWS CLI to check the capacity:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   aws wafv2 check-capacity &lt;span class="nt"&gt;--scope&lt;/span&gt; REGIONAL &lt;span class="nt"&gt;--rules&lt;/span&gt; file://rules.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output will look 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;"Capacity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;15&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;This command returns the total WCU requirement for your specified rules. Ensure it doesn't exceed 5,000 WCUs for a single Web ACL.&lt;/p&gt;

&lt;h4&gt;
  
  
  Integrating Capacity Check with Terraform
&lt;/h4&gt;

&lt;p&gt;To avoid deployment failures due to WCU limits, integrate the capacity check into your Terraform workflow using a shell script:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create a Shell Script&lt;/strong&gt;:
Write a script (&lt;code&gt;check_capacity.sh&lt;/code&gt;) to perform the capacity check:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

   &lt;span class="nv"&gt;CAPACITY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;aws wafv2 check-capacity &lt;span class="nt"&gt;--scope&lt;/span&gt; REGIONAL &lt;span class="nt"&gt;--rules&lt;/span&gt; file://rules.json | jq &lt;span class="s1"&gt;'.Capacity'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CAPACITY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-gt&lt;/span&gt; 5000 &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
     &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Error: Capacity units exceeded. Current capacity: &lt;/span&gt;&lt;span class="nv"&gt;$CAPACITY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
     &lt;span class="nb"&gt;exit &lt;/span&gt;1
   &lt;span class="k"&gt;else
     &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Capacity check passed. Current capacity: &lt;/span&gt;&lt;span class="nv"&gt;$CAPACITY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
     &lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;TERRAFORM_CAPACITY_CHECK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;passed
   &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Integrate with Terraform&lt;/strong&gt;:
Modify your Terraform workflow to include the script:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   ./check_capacity.sh

   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TERRAFORM_CAPACITY_CHECK&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"passed"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
     &lt;/span&gt;terraform apply
   &lt;span class="k"&gt;else
     &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Terraform apply aborted due to capacity issues."&lt;/span&gt;
   &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By incorporating this script, you ensure that your Terraform deployments only proceed if the WCU requirements are within limits, preventing potential failures and downtime.&lt;/p&gt;

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

&lt;p&gt;Handling WCU limits is crucial for successful AWS WAF deployments using Terraform. By leveraging the &lt;code&gt;check-capacity&lt;/code&gt; command in AWS CLI and integrating it into your Terraform workflow, you can proactively manage capacity and avoid deployment issues. This approach ensures a smoother, more reliable infrastructure management process especially until terraform starts to support a similar built-in functionality.&lt;/p&gt;

&lt;p&gt;For further reading, check the official &lt;a href="https://docs.aws.amazon.com/waf/latest/developerguide/aws-waf-capacity-units.html"&gt;AWS WAF documentation on WCUs&lt;/a&gt; and the &lt;a href="https://awscli.amazonaws.com/v2/documentation/api/latest/reference/wafv2/check-capacity.html"&gt;AWS CLI &lt;code&gt;check-capacity&lt;/code&gt; command reference&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>aws</category>
      <category>webacl</category>
      <category>waf</category>
    </item>
  </channel>
</rss>
