<?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: Guillaume Duboc</title>
    <description>The latest articles on DEV Community by Guillaume Duboc (@guillaumeduboc).</description>
    <link>https://dev.to/guillaumeduboc</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%2F790477%2Fd665a8f7-084d-4f76-8e36-3d7336e4ad4a.png</url>
      <title>DEV Community: Guillaume Duboc</title>
      <link>https://dev.to/guillaumeduboc</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/guillaumeduboc"/>
    <language>en</language>
    <item>
      <title>Deploy a Lambda with a static IP for FREE 💸</title>
      <dc:creator>Guillaume Duboc</dc:creator>
      <pubDate>Wed, 11 Oct 2023 08:52:55 +0000</pubDate>
      <link>https://dev.to/slsbytheodo/deploy-a-lambda-with-a-static-ip-for-free-4e0l</link>
      <guid>https://dev.to/slsbytheodo/deploy-a-lambda-with-a-static-ip-for-free-4e0l</guid>
      <description>&lt;p&gt;&lt;a href="https://twitter.com/GuillaumeDuboc" class="ltag_cta ltag_cta--branded"&gt;Follow me on X (former twitter) 🚀&lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;In this article, we will learn how to assign a static IP to a Lambda for free using the AWS CDK 💸&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with Lambdas and static IPs
&lt;/h2&gt;

&lt;p&gt;It's actually easy to assign a static IP to a Lambda, as shown by &lt;a href="https://dev.to/slsbytheodo/deploying-a-lambda-with-a-static-ip-has-never-been-so-simple-5dke"&gt;this article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;❌ The only caveat is that we need to use a NAT Gateway and it is quite expensive ($30/month).&lt;/p&gt;

&lt;p&gt;A few weeks ago I stumbled across this &lt;a href="https://theburningmonk.com/2023/09/static-ip-for-lambda-ingress-egress-and-bypassing-the-dreaded-nat-gateway/"&gt;great article by Yan Cui&lt;/a&gt;. He explains how to outsmart AWS and exploit the resources they create in the background for us.&lt;/p&gt;

&lt;p&gt;Basically :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;every time you create a Lambda in a vpc, AWS creates an ENI (Elastic Network Interface)&lt;/li&gt;
&lt;li&gt;we can programmatically extract the ENI ID&lt;/li&gt;
&lt;li&gt;we can then attach an Elastic IP to the corresponding ENI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The idea in Yan's article is amazing but the Infrastructure as Code implementation is a bit complex. &lt;strong&gt;Here is how I was able to do it using the AWS CDK.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying a Lambda with a static IP using ENIs
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Create a Lambda in a VPC
&lt;/h3&gt;

&lt;p&gt;First, we need to create a Lambda in a VPC. It should be in a public subnet so that it can access the internet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-cdk-lib&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;vpc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vpc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Vpc&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;natGateways&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="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// we'll see later why we need this&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SecurityGroup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SecurityGroup&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;vpc&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;func&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_lambda_nodejs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;NodejsFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TestFunc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// cdk wants to make sure that the lambda can access the internet&lt;/span&gt;
  &lt;span class="na"&gt;allowPublicSubnet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// the lambda needs to be in a public subnet&lt;/span&gt;
  &lt;span class="na"&gt;vpcSubnets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;subnets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;publicSubnets&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;securityGroups&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;sg&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your lambda already exists, make sure you move it to a public subnet.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Extract the Elastic Network Interface ID
&lt;/h3&gt;

&lt;p&gt;Now that we have a Lambda in a VPC, we need to find the ENI ID aws created automatically.&lt;/p&gt;

&lt;p&gt;Let's try like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;eni&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;securityGroups&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="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;defaultChild&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CfnNetworkInterface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Well actually, it doesn't work. 🙀&lt;/p&gt;

&lt;p&gt;The ENI is not created yet when the CDK is executed. The resource is created by the AWS Cloudformation service when the lambda is deployed. We need to find a way to extract the ENI ID after the lambda has been created during the rest of the deployment.&lt;/p&gt;

&lt;p&gt;The solution is to use a custom resource. It allows us to execute a lambda during the deployment, and fetch the ENI ID using the AWS SDK. We can do that easily using the &lt;a href="https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.custom_resources.AwsCustomResource.html"&gt;&lt;code&gt;AwsCustomResource&lt;/code&gt;&lt;/a&gt; construct.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;custom_resources&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AwsCustomResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;customResource&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;onCreate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;physicalResourceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;custom_resources&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PhysicalResourceId&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="c1"&gt;// adds a dependency on the security group and the subnet&lt;/span&gt;
      &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;sg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;securityGroupId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;publicSubnets&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="nx"&gt;subnetId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-CustomResource`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;EC2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;describeNetworkInterfaces&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;Filters&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="na"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;interface-type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;Values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lambda&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;group-id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;Values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;sg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;securityGroupId&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="na"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;subnet-id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;Values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;publicSubnets&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="nx"&gt;subnetId&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="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;policy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;custom_resources&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AwsCustomResourcePolicy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromSdkCalls&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;custom_resources&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AwsCustomResourcePolicy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ANY_RESOURCE&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="c1"&gt;// adds a dependency on the lambda function&lt;/span&gt;
&lt;span class="nx"&gt;cr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addDependency&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// we can now extract the ENI ID&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;eniId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getResponseField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;NetworkInterfaces.0.NetworkInterfaceId&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the snippet above we are calling &lt;a href="https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/ec2/command/DescribeNetworkInterfacesCommand/"&gt;&lt;code&gt;describeNetworkInterfaces&lt;/code&gt;&lt;/a&gt; function of the AWS SDK. We only keep the ENIs attached to a Lambda, in my security group and my public subnet. Adding our lambda as a dependency ensures that the custom resource is executed after the lambda is created.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Attach an Elastic IP to the ENI - (the easiest one)
&lt;/h3&gt;

&lt;p&gt;Now that we have the ENI ID, we can attach an Elastic IP to it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// const eniId = cr.getResponseField("NetworkInterfaces.0.NetworkInterfaceId");&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;eip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CfnEIP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;subnet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;EIP&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;domain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vpc&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CfnEIPAssociation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;EIPAssociation&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;networkInterfaceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;eniId&lt;/span&gt;
  &lt;span class="na"&gt;allocationId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;eip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attrAllocationId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Let's put it all together
&lt;/h3&gt;

&lt;p&gt;We now have all the pieces we need to create a lambda with a static IP. We were able to do it for a single subnet, we just need to repeat the process for all the public subnets our lambda needs to be in.&lt;/p&gt;

&lt;p&gt;You can find the full code &lt;a href="https://github.com/guillaumeduboc/free-static-ip/blob/main/lib/free-static-ip-stack.ts"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;We can use attach a static IP to a Lambda for FREE using ENIs 💸&lt;/li&gt;
&lt;li&gt;We can use the &lt;a href="https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.custom_resources.AwsCustomResource.html"&gt;&lt;code&gt;AwsCustomResource&lt;/code&gt;&lt;/a&gt; construct to perform AWS SDK calls during the deployment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Make sure you enjoy your free static IP while it lasts. Elastic IPs will cost $3/month as of January 2024.&lt;/p&gt;

&lt;p&gt;Although this is great for reducing your costs, you should not use it for production environments. AWS might change the way they manage ENIs in the future and break your infrastructure. Furthermore, &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/foundation-networking.html#:~:text=If%20a%20Lambda%20function%20remains%20idle%20for%20consecutive%20weeks%2C%20Lambda%20reclaims%20the%20unused%20Hyperplane%20ENIs"&gt;if you're Lambda is not used in a while AWS will delete the ENI&lt;/a&gt;. To avoid this you can setup a cron job to keep the ENI.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>serverless</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Supercharge your geolocalized DynamoDB Queries with Z-Order Indexing 🚀</title>
      <dc:creator>Guillaume Duboc</dc:creator>
      <pubDate>Tue, 18 Apr 2023 12:06:03 +0000</pubDate>
      <link>https://dev.to/slsbytheodo/supercharge-your-geolocalized-dynamodb-queries-with-z-order-indexing-2oo8</link>
      <guid>https://dev.to/slsbytheodo/supercharge-your-geolocalized-dynamodb-queries-with-z-order-indexing-2oo8</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Embark on our journey to enhance DynamoDB geospatial queries with custom Z-Order indexing implementation! Discover calculating Z-addresses, fine-tuning queries, and results.  Although performance is equivalent to Mongo Atlas, maintaining your own Z-Order indexing is very challenging. We recommend &lt;strong&gt;using non DynamoDB off-the-shelf alternatives&lt;/strong&gt;.&lt;/p&gt;




&lt;p&gt;This article will guide you through our experimentation of a Z-Order index on DynamoDB, based on the excellent work by Zack Slayton in &lt;a href="https://aws.amazon.com/blogs/database/z-order-indexing-for-multifaceted-queries-in-amazon-dynamodb-part-1/" rel="noopener noreferrer"&gt;his article on Z-order indexing&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When it comes to handling complex, geographic queries in Amazon DynamoDB, there is no off the shelf solution. Z-Order indexing offers an efficient and powerful solution to this problem. It is particularly suited for querying a small zone around a geolocation.&lt;/p&gt;

&lt;p&gt;Before diving in, let’s go through some of Z-Order core concepts.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🤖 All our implementations of the functions we are describing are available on &lt;a href="https://gist.github.com/valentinbeggi/0cca29e51f52fb3556408de3b2b23a87" rel="noopener noreferrer"&gt;this gist&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Creating Z-Addresses for Your Records 🏷️
&lt;/h2&gt;

&lt;p&gt;The first step in implementing a Z-Order index is calculating the Z-addresses for your records. A Z-address is a single number representing a tuple of field values. To calculate a Z-address, simply interleave the bits of each field in the record. Check out the examples provided in the &lt;a href="https://aws.amazon.com/blogs/database/z-order-indexing-for-multifaceted-queries-in-amazon-dynamodb-part-1/" rel="noopener noreferrer"&gt;base article&lt;/a&gt; to see how this is done.&lt;/p&gt;

&lt;p&gt;Once you can generate a z-order index, apply it to your dataset and store it in DynamoDB. The SK will be the z-order Index.&lt;/p&gt;

&lt;h2&gt;
  
  
  Crafting Queries for Data Retrieval 🔍
&lt;/h2&gt;

&lt;p&gt;With Z-addresses in hand, you can now build queries to retrieve data. This step was much more challenging than we thought.&lt;/p&gt;

&lt;p&gt;Begin by defining a minimum and maximum value for the range of items you want to read. Then, create two records representing the lower and upper bounds of this range. Translate these records into Z-addresses to form the query space.&lt;/p&gt;

&lt;p&gt;However, if your query range intersects with "seams" in the Z-order curve, you'll need to use two functions to avoid irrelevant regions in the search space: &lt;code&gt;isRelevant&lt;/code&gt; and &lt;code&gt;zDivide&lt;/code&gt;. These functions help narrow down the search space and minimize garbage data.&lt;/p&gt;

&lt;h2&gt;
  
  
  TypeScript Implementation of Z-Order Index 📚
&lt;/h2&gt;

&lt;p&gt;You can find our implementation in &lt;a href="https://gist.github.com/valentinbeggi/0cca29e51f52fb3556408de3b2b23a87" rel="noopener noreferrer"&gt;this gist&lt;/a&gt;. We left it as a PoC and consider it to be far from prod ready&lt;/p&gt;

&lt;p&gt;We parametrized the algorithm to be able to optimize the precision of our Z-Order indexes and the data outside of our search box.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Limitations and Trade-offs of Z-Order Indexing 🤔&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The main limitation of Z-Order indexing is the accuracy of your queries. This is due to the conversion from latitude/longitude to an index&lt;/p&gt;

&lt;p&gt;You can optimize the precision of your Z-Order indexes by tweaking the parameters of the algorithm.&lt;/p&gt;

&lt;p&gt;Our implementation also doesn’t include more than 2D data, you will not be able to query on timestamp as an index for example.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up 🎁
&lt;/h2&gt;

&lt;p&gt;Z-Order indexing significantly improves the efficiency of your DynamoDB queries when fetching geographic data. By implementing the Z-Order index and utilizing functions &lt;code&gt;zDivide&lt;/code&gt;, you can minimize garbage data and optimize your database's performance.&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%2Fw3wgffzfvybwrjjivdcd.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%2Fw3wgffzfvybwrjjivdcd.png" alt="ZOrder Indexing query times"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our feeling is that handling your own geo-index is challenging and hard to maintain. If it is not critical for your use case to handle it yourself, we recommend you use off the shelf solutions such as &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MongoDB Atlas&lt;/li&gt;
&lt;li&gt;Postgis Plugin on your Postgre Database&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With the information provided in this article and the base knowledge from Zack Slayton's &lt;a href="https://aws.amazon.com/blogs/database/z-order-indexing-for-multifaceted-queries-in-amazon-dynamodb-part-1/" rel="noopener noreferrer"&gt;article on Z-Order indexing&lt;/a&gt;, you're now equipped to supercharge your DynamoDB queries with Z-Order indexing. Happy querying! 🚀🎉&lt;/p&gt;

&lt;p&gt;Written with ❤️ by &lt;a href="https://dev.to/guillaumeduboc"&gt;@Guillaume Duboc&lt;/a&gt; and &lt;a href="https://dev.to/valentinbeggi"&gt;@Valentin Beggi&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>database</category>
      <category>serverless</category>
      <category>aws</category>
    </item>
    <item>
      <title>Monitor and Debug your Serverless Applications Painlessly with Epsagon</title>
      <dc:creator>Guillaume Duboc</dc:creator>
      <pubDate>Tue, 08 Feb 2022 14:03:45 +0000</pubDate>
      <link>https://dev.to/slsbytheodo/monitor-and-debug-your-serverless-applications-painlessly-with-epsagon-258o</link>
      <guid>https://dev.to/slsbytheodo/monitor-and-debug-your-serverless-applications-painlessly-with-epsagon-258o</guid>
      <description>&lt;p&gt;If you develop Serverless Applications on AWS, you know how painful it can be to monitor and debug your application from the AWS Console. &lt;/p&gt;

&lt;p&gt;A few weeks back, we at Kumo shared &lt;a href="https://dev.to/kumo/we-tested-the-best-serverless-monitoring-solutions-so-you-dont-have-to-121m"&gt;why Epsagon is our favorite solution for monitoring our Serverless Applications&lt;/a&gt;, after testing most of the Serverless monitoring solutions. Epsagon is quick to install, has instant alarms, great request tracing and enables you to monitor custom KPIs.&lt;/p&gt;

&lt;p&gt;But installing a powerful tool isn’t enough. You need to set it up the right way and use it frequently. The following article will help you stay efficient and well organized while setting up Epsagon for the best monitoring experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;▶️  For the best setup, check the pre-flight checklist.&lt;/p&gt;

&lt;p&gt;▶️  Use the Epsagon Serverless Framework plugin.&lt;/p&gt;

&lt;p&gt;▶️  Add custom KPIs if desired by calling the Epsagon SDK in you handler&lt;/p&gt;

&lt;p&gt;▶️  Setup lambda alarms on an existing and used channel&lt;/p&gt;

&lt;p&gt;▶️  Put back together incomplete traces with a custom KPI&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Epsagon ?
&lt;/h2&gt;

&lt;p&gt;Epsagon comes right out of the box with : &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;dashboards you can customize to visualize your application’s performance&lt;/li&gt;
&lt;li&gt;alarms you can configure to report errors on your desired channels&lt;/li&gt;
&lt;li&gt;traces, representing all operations occurring across various services in response of a single trigger. This enables you to quickly debug your serverless application.&lt;/li&gt;
&lt;li&gt;custom metrics tailored to your application business and technical KPIs using Epsagon SDK&lt;/li&gt;
&lt;/ul&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%2F6zk1sfj53yjxmey9luj2.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%2F6zk1sfj53yjxmey9luj2.png" alt="traces flow"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A simple UI provides both an architecture diagram as well as a timeline view of each trace, depending on your needs&lt;/p&gt;

&lt;h2&gt;
  
  
  Epsagon pre-flight checklist &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Before starting the Epsagon installation, in order to have the best quality of monitoring, you should ask yourself the following 3 questions. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What are my application characterizing identifiers ?

&lt;ul&gt;
&lt;li&gt;Think user email, order id&lt;/li&gt;
&lt;li&gt;Think technical KPIs such as &lt;code&gt;modelName&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;What data should be kept private?

&lt;ul&gt;
&lt;li&gt;Think identification token, API keys&lt;/li&gt;
&lt;li&gt;Think private user data&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;What’s my preferred notification channel ?

&lt;ul&gt;
&lt;li&gt;The tool you already use the most might be ideal to receive notification. Nobody likes a never ending pile of automated message on a dedicated and long-forgotten Slack channel&lt;/li&gt;
&lt;li&gt;A tool where you can tag someone or indicate you are taking care of the bug is the best&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;You are now ready to install Epsagon. You'll have to choose how to install it. Lucky for you, I have tested all of them and resumed it in the next section&lt;/p&gt;

&lt;h2&gt;
  
  
  Which setup should I use ? &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Epsagon gives you 3 different ways of connecting your app to its monitoring solution. You can activate auto-tracing from the Epsagon App, add the Epsagon Serverless Framework plugin to your serverless config or use the Epsagon SDK in all your handlers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pros and Cons
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Auto-Tracing&lt;/th&gt;
&lt;th&gt;Serverless Framework plugin&lt;/th&gt;
&lt;th&gt;Epsagon SDK&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Time&lt;/td&gt;
&lt;td&gt;✅  Fastest&lt;/td&gt;
&lt;td&gt;✅  Fast&lt;/td&gt;
&lt;td&gt;❌  Long Setup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compatibility&lt;/td&gt;
&lt;td&gt;✅  compatible with Epsagon SDK&lt;/td&gt;
&lt;td&gt;✅  you can call the Epsagon SDK in your handler&lt;/td&gt;
&lt;td&gt;✅  compatible with auto-trace&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Customization&lt;/td&gt;
&lt;td&gt;❌  almost impossible&lt;/td&gt;
&lt;td&gt;✅  very easy in the serverless config, but not complete&lt;/td&gt;
&lt;td&gt;✅  completely customizable&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I recommend using the serverless plugin, with appropriate parameters. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Give each stack a specific name.&lt;/li&gt;
&lt;li&gt;Indicate Lambda Functions you don’t wish to trace&lt;/li&gt;
&lt;li&gt;Declare the sensitive data you don’t wish to trace&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is still possible to add a custom metric or a warning inside a Lambda Function with the SDK on a per use case basis. &lt;/p&gt;

&lt;h2&gt;
  
  
  Setup with the Serverless Framework plugin
&lt;/h2&gt;

&lt;p&gt;The Serverless Framework plugin enables you to adapt your setup to your trace(s). Keep in mind these point before the installation &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It traces all Lambda Functions of your stack immediately after the first deploy&lt;/li&gt;
&lt;li&gt;Configure stack, and function monitoring in your &lt;a href="https://www.npmjs.com/package/serverless-plugin-epsagon#configuration" rel="noopener noreferrer"&gt;serverless config file&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Filter sensitive data on your AWS account before it’s shipped to Epsagon backend

&lt;ul&gt;
&lt;li&gt;This data will not be sent in the trace and you will not see it in the tags anymore. Otherwise the data is sent on Epsagon’s stack to be accessible on the app&lt;/li&gt;
&lt;li&gt;list them in &lt;code&gt;ignoredKeys&lt;/code&gt; in your config&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Ignore specific ingoing or outgoing http request

&lt;ul&gt;
&lt;li&gt;specify an array of url patterns in &lt;code&gt;urlsToIgnore&lt;/code&gt; in your config&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Trace Step Functions inside a State Machine

&lt;ul&gt;
&lt;li&gt;specify in the config &lt;code&gt;wrapper: 'stepLambdaWrapper'&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;You can now follow the &lt;a href="https://www.npmjs.com/package/serverless-plugin-epsagon" rel="noopener noreferrer"&gt;installation instruction&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the best integration, you will have to deploy an Epsagon stack on your AWS account.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Log in to &lt;a href="https://app.epsagon.com/quickstart" rel="noopener noreferrer"&gt;https://app.epsagon.com/quickstart&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Follow the quick start and click on &lt;code&gt;Monitor Your Environment&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Select AWS&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Integrate AWS&lt;/code&gt; will redirect you to the AWS console, where you can deploy the Epsagon stack&lt;/li&gt;
&lt;/ul&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%2Fjv6y6pxo3wrs1k6dh6bj.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%2Fjv6y6pxo3wrs1k6dh6bj.png" alt="deploy epsagon stack"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding custom business KPI &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Since the Epsagon plugin requires the &lt;code&gt;epsagon&lt;/code&gt; module, you can use the SDK inside your Lambda Function to monitor any KPI you want. &lt;/p&gt;

&lt;p&gt;Here is a snippet as example&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;epsagon&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;epsagon&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;main&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="c1"&gt;// my function handler&lt;/span&gt;
    &lt;span class="nx"&gt;epsagon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;myCustomKPI&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;42&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 plugin will take care of initiating Epsagon and wrapping the handler.&lt;/p&gt;

&lt;p&gt;Similarly, you can use &lt;code&gt;setError&lt;/code&gt; and &lt;code&gt;setWarning&lt;/code&gt; to have an event in the Epsagon App, without throwing an error in your code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up alarms&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;To maintain the quality of your app, you need to be notified whenever an error occurs. Automatic alerts limit bug impact as we are aware of its presence sooner.&lt;/p&gt;

&lt;p&gt;You can easily set up an alarm on lambdas, or on a metric you selected&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Exception&lt;/code&gt; refers to Errors thrown by your lambda&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Function Error&lt;/code&gt; refers to a Lambda Service error&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Out Of Memory&lt;/code&gt; refers to a Lambda  Function running out of memory&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Timeout&lt;/code&gt; refers to a Lambda Function reaching its configured timeout&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Insight&lt;/code&gt; refers to being close to one of the two previous limits&lt;/li&gt;
&lt;/ul&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%2Fkz7afnpsdqxea8e8srd4.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%2Fkz7afnpsdqxea8e8srd4.png" alt="lambda alerts"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up my traces
&lt;/h2&gt;

&lt;p&gt;In a serverless architecture your operations are often distributed across multiple different services. In your AWS console, it is painful and time consuming to investigate the origin of a bug. Tracing gives you the possibility to quickly understand the context of your error and its timeline. &lt;/p&gt;

&lt;p&gt;You should index the identifiers you selected before starting the installation in order to make them easily searchable throughout your traces data.&lt;/p&gt;

&lt;p&gt;Example : Considering an e-commerce application, you may have some of your EventBridge events containing an &lt;code&gt;orderId&lt;/code&gt; attribute. Indexing this attribute to make it searchable will allow you to easily recover all traces resulting from any EventBridge events related to a specific order.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For a simple tag you can add it by clicking the + on the right&lt;/li&gt;
&lt;/ul&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%2Fja5d918rf7m7xkj6gjr2.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%2Fja5d918rf7m7xkj6gjr2.png" alt="tag a label in trace"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can expand a nested attribute and visualize the entire data&lt;/li&gt;
&lt;/ul&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%2Fk15rp6h514abj2ao8878.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%2Fk15rp6h514abj2ao8878.png" alt="expand nested attributes in trace"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To tag as searchable a nested property, click on &lt;code&gt;Set Searchable Tags&lt;/code&gt;, and pick the tag you are interested in&lt;/li&gt;
&lt;/ul&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%2Fpsq5lkqt4cf5xfmsdn2m.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%2Fpsq5lkqt4cf5xfmsdn2m.png" alt="set label as searchable in trace"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can now create a dashboard, an alarm or find a trace with that specific data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up a dashboard
&lt;/h2&gt;

&lt;p&gt;You can create graphs, and thus dashboards or alarms on 2 types of metrics :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Epsagon traces : they are great for monitoring custom metrics and lambda oriented data (trigger data, return data)&lt;/li&gt;
&lt;li&gt;CloudWatch metrics : these are the same metrics than the ones in CloudWatch, but you can easily create a custom graph&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To create a good looking, changeable dashboard, you can create variables. These are modifiable at the top of your dashboard. You can refer to them in the graphs of your dashboard. &lt;/p&gt;

&lt;p&gt;💡 ⚠️ Beware, if an alias is used to specify the region, auto-complete will be broken&lt;br&gt;
→ fix : pick a region, then fill the parameters and finally switch back to alias as region&lt;/p&gt;

&lt;h3&gt;
  
  
  Finally, you are almost done !
&lt;/h3&gt;

&lt;p&gt;In order to ensure your application monitoring is correctly setup, you should perform a simple check : does all operations across all services resulting from a single trigger appear in one single trace ? &lt;/p&gt;

&lt;p&gt; ▶️  If you do, congrats 🎉! You can now safely operate your application and react efficiently in the case of a problem. &lt;/p&gt;

&lt;p&gt; ▶️  If not, you need to “manually” assemble traces : keep on reading.&lt;/p&gt;

&lt;h2&gt;
  
  
  What if it doesn’t work? &lt;a&gt;&lt;/a&gt;
&lt;/h2&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%2Fm88tm5yy9af9x4xx44so.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%2Fm88tm5yy9af9x4xx44so.png" alt="incomplete trace"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What if instead of having a single, complete trace, you have a cropped one. &lt;/p&gt;

&lt;p&gt;This is of course not an ideal situation but it can happen. Some services might not be instrumented yet (&lt;a href="https://epsagon.com/integrations/" rel="noopener noreferrer"&gt;here is a list of supported services&lt;/a&gt;). In other cases, some API of the AWS SDK itself might be problematic (here EventBridge JavaScript SDK v2 is properly traced but not v3). &lt;/p&gt;

&lt;p&gt;In that case, you should &lt;a href="https://github.com/epsagon/epsagon-node/issues" rel="noopener noreferrer"&gt;open an issue&lt;/a&gt; or &lt;a href="//mailto:support@epsagon.com"&gt;contact the Epsagon team&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;While you wait for an updated Epsagon instrumentation, you can implement a contingency strategy.&lt;/p&gt;

&lt;p&gt;You can use custom metrics to log the event Id. Here is a code snippet representing this example&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// sendMesage.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;EventBridge&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PutEventsCommand&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-sdk/client-eventbridge&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;epsagon&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;epsagon&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;eventBridge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;EventBridge&lt;/span&gt;&lt;span class="p"&gt;({});&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handler&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="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;eventBridge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PutEventsCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Entries&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Entries&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="nx"&gt;EventId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;epsagon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;EventBridgeEntries&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Entries&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="nx"&gt;EventId&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// eventBridgeWorker.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;epsagon&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;epsagon&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;heandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="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;epsagon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;EventBridgeEntries&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fh7ahakc1b6ptkvpmstu1.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%2Fh7ahakc1b6ptkvpmstu1.png" alt="labelled traces"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By clicking on the search icon next to the label, you can find the all the Lambda Function that consume or emitted the event.&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%2Fs12p3ue4a4h2atkcd6kl.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%2Fs12p3ue4a4h2atkcd6kl.png" alt="search trace"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can now connect the 2 traces ! &lt;/p&gt;

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

&lt;p&gt;In order to make the most of Epsagon as a monitoring solution, I believe you should&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check the pre-flight checklist&lt;/li&gt;
&lt;li&gt;use the Serverless Framework Plugin for Epsagon&lt;/li&gt;
&lt;li&gt;Add custom KPIs to monitor your application&lt;/li&gt;
&lt;li&gt;set up alarms to have the shortest lead time when a bug occurs&lt;/li&gt;
&lt;li&gt;use traces to find the origin of your bugs and be able to reproduce your errors&lt;/li&gt;
&lt;li&gt;use custom metrics to link incomplete traces&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Finally, monitoring your Serverless Application will be painless 🚀
&lt;/h3&gt;

&lt;p&gt;Don’t hesitate to share in the comment section your tips and tricks when using Epsagon !&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Guillaume Duboc is software engineer at Kumo, serverless expertise by &lt;a href="https://www.theodo.fr/" rel="noopener noreferrer"&gt;Theodo&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>monitoring</category>
      <category>serverless</category>
      <category>aws</category>
    </item>
  </channel>
</rss>
