<?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: anandsunderraman</title>
    <description>The latest articles on DEV Community by anandsunderraman (@anandsunderraman).</description>
    <link>https://dev.to/anandsunderraman</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%2F238533%2F4c09d2e3-bc8b-49a6-9932-202dd80c3259.png</url>
      <title>DEV Community: anandsunderraman</title>
      <link>https://dev.to/anandsunderraman</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/anandsunderraman"/>
    <language>en</language>
    <item>
      <title>Navigating Microservices Code Repos</title>
      <dc:creator>anandsunderraman</dc:creator>
      <pubDate>Thu, 20 Jan 2022 02:03:22 +0000</pubDate>
      <link>https://dev.to/anandsunderraman/navigating-microservices-code-repos-1cmk</link>
      <guid>https://dev.to/anandsunderraman/navigating-microservices-code-repos-1cmk</guid>
      <description>&lt;p&gt;This post is a repost from my personal blog &lt;a href="https://thecodesphinx.com/2022/01/19/code-repos/"&gt;The Code Sphinx&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This happened when I was working for one of my previous employers.&lt;br&gt;
I had just joined the company and was working on a microservice that was consuming a REST api exposed by another microservice.&lt;br&gt;
There was this JIRA ticket I was working on and I was not sure about the data model exposed by this REST api call. At this point in time the adoption to &lt;a href="https://swagger.io/specification/"&gt;OpenAPI / Swagger&lt;/a&gt; / &lt;a href="https://raml.org/"&gt;RAML&lt;/a&gt; was just beginning. I was new and was wondering whom I should reach out to.&lt;br&gt;
Just then my colleague, who had joined a month before me, sent me a link to the codebase of this repository that implemented this REST api.&lt;br&gt;
He also went ahead and showed me the Crucible tool that showed me code reviews to this repo.&lt;br&gt;
That was an "Aha !!" moment for me. It opened up new avenues to learn and to make new connections across teams.&lt;br&gt;
Until then I had never explored a code repository that I did not work on.&lt;br&gt;
But now, since I was seeking an answer to my question, it was motivation enough to explore this code repository.&lt;br&gt;
It was like solving a puzzle and kept me hooked until I found an answer to the question.&lt;/p&gt;

&lt;h2&gt;
  
  
  Options to explore a new code repo
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;ReadMe / Wiki Documentation&lt;/li&gt;
&lt;li&gt;Read the code&lt;/li&gt;
&lt;li&gt;Unit Tests&lt;/li&gt;
&lt;li&gt;Running the app&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  ReadMe / Wiki Documentation
&lt;/h3&gt;

&lt;p&gt;The general expectation is that any good code repository has a good readme that talks about&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What does the project / codebase do ?&lt;/li&gt;
&lt;li&gt;How to set it up to run on a local machine ?&lt;/li&gt;
&lt;li&gt;How to contribute to it ?
The above are generally true for well maintained open source repositories.
If there is a readme with accurate information then look no further, literally !!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Many organizations use other products to maintain internal documentation. A popular product adopted being &lt;a href="https://www.atlassian.com/software/confluence"&gt;Confluence&lt;/a&gt;. &lt;code&gt;Confluence&lt;/code&gt; has a good search capability. A quick search about the repo name or the project name should list &lt;code&gt;Confluence&lt;/code&gt; pages that list or mention this repo. This also might give insight into the context of the project and how it fits in the organization.&lt;/p&gt;

&lt;h3&gt;
  
  
  Read the code
&lt;/h3&gt;

&lt;p&gt;This should be the most obvious choice. But the irony is, there is nothing obvious about reading source code. Source code is the ultimate source of truth.&lt;br&gt;
It takes a lot of experience to try and figure out the flow of control in an app just by reading the code.&lt;br&gt;
I am no expert but I do try poking around the code to understand what certain parts of the code do.&lt;/p&gt;

&lt;p&gt;A quick way to think of an app is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Bootstrapping / App initialization / Startup&lt;/li&gt;
&lt;li&gt;Dependencies&lt;/li&gt;
&lt;li&gt;Points of integration into the app&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Bootstrapping / App initialization / Startup
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Spring Boot Application: Look for Application.java file or a file with &lt;code&gt;@SpringBootApplication&lt;/code&gt; annotation&lt;/li&gt;
&lt;li&gt;Node.js: Look for &lt;code&gt;index.js&lt;/code&gt; or look at &lt;code&gt;package.json&lt;/code&gt; to see what starts the app.&lt;/li&gt;
&lt;li&gt;Go: Look for &lt;code&gt;main.go&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Dependencies
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Spring Boot Application: Look at the application properties or application yaml file.&lt;/li&gt;
&lt;li&gt;Node.js / Go Lang: Look for the environment files or look at the starter / bootstrap file to see which files it refers to load the configurations.&lt;/li&gt;
&lt;li&gt;Look for the infrastructure code to see where and what environment variables are set&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Points of integration
&lt;/h4&gt;

&lt;p&gt;An app can have multiple types of integration.&lt;br&gt;
The most common ones being&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;REST API&lt;/li&gt;
&lt;li&gt;Event driven interactions&lt;/li&gt;
&lt;li&gt;Database (DB) interactions&lt;/li&gt;
&lt;/ol&gt;

&lt;h5&gt;
  
  
  REST API
&lt;/h5&gt;

&lt;ol&gt;
&lt;li&gt;Spring controllers in a Java Spring Boot based application&lt;/li&gt;
&lt;li&gt;Routes / Middleware in a express node.js based application&lt;/li&gt;
&lt;li&gt;Search the code for REST API &lt;code&gt;path&lt;/code&gt; and figure out what is the handler for the code&lt;/li&gt;
&lt;li&gt;Search the code for controllers&lt;/li&gt;
&lt;/ol&gt;

&lt;h5&gt;
  
  
  Event driven interactions
&lt;/h5&gt;

&lt;ol&gt;
&lt;li&gt;Search the code for "Listeners" or "Publishers"&lt;/li&gt;
&lt;li&gt;Search for code references for the queue / topic name&lt;/li&gt;
&lt;li&gt;Based on the code references for the queue or topic name, search for event handlers &lt;code&gt;publish&lt;/code&gt; messages or &lt;code&gt;subscribe&lt;/code&gt; messages.&lt;/li&gt;
&lt;/ol&gt;

&lt;h5&gt;
  
  
  Database (DB) interactions
&lt;/h5&gt;

&lt;ol&gt;
&lt;li&gt;Search the code / application configuration for the connection string to the database.&lt;/li&gt;
&lt;li&gt;See if there are any &lt;code&gt;.sql&lt;/code&gt; files in the code base that define the DDL&lt;/li&gt;
&lt;li&gt;See if the code uses any sql migration tool and what scripts it might use.
If thee DB connection string is obtained, one can easily connect to the &lt;code&gt;dev&lt;/code&gt; instance of the DB using a client and try to understand the table and get a hang of the model that this app interacts with.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Again all of this is just a shot in the dark. But over a period of time and with experience one can narrow down areas to look at and inspect.&lt;/p&gt;

&lt;h3&gt;
  
  
  Unit Tests / Integration Tests
&lt;/h3&gt;

&lt;p&gt;So what do we do when the instructions in the readme are not accurate or in the worst case there is no readme at all ?&lt;br&gt;
Many times I have come across libraries that do not have great documentation for their api.&lt;br&gt;
In such situations I read through the unit tests to see how the library / api is being used.&lt;br&gt;
The hope is that the developer cares for the code developed and has tested all the functionality that the api / library has to offer.&lt;br&gt;
This is like a backdoor to documentation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Running the app
&lt;/h3&gt;

&lt;p&gt;The last resort is to run the app.&lt;br&gt;
This is where the fun and exciting part begins.&lt;br&gt;
&lt;strong&gt;&lt;em&gt;One must be careful not to get into a rabbit hole trying to get the app running. This effort must be time-boxed.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I have worked across technologies like Java, Go and Node.js.&lt;br&gt;
So as a developer I am familiar with how to run a Java app or a Go app or a Node.js app.&lt;br&gt;
I just attempt to get the app running, fingers crossed.&lt;br&gt;
More often than not there are errors running the app and now is where the exciting part comes.&lt;br&gt;
I start to resolve the errors one by one.&lt;br&gt;
More often than not the errors are related to the application configurations.&lt;br&gt;
It is a matter of figuring out which configuration is missing or what needs to be tweaked to overcome that error.&lt;br&gt;
It is like being a detective solving the clues one by one.&lt;/p&gt;

&lt;p&gt;First step is to clone the repository on your local machine.&lt;br&gt;
The next step is to download the dependencies for your application and download them.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Spring Boot Application using Maven
&lt;code&gt;mvn clean install&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Node.js Application
&lt;code&gt;npm install&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Golang Code
&lt;code&gt;go mod download&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Java Spring Boot Applications
&lt;/h4&gt;

&lt;p&gt;I have been lucky that my organizations have always been able to provide me a license to use &lt;a href="https://www.jetbrains.com/idea/"&gt;IntelliJ IDEA&lt;/a&gt;.&lt;br&gt;
With IntelliJ, I just click on run on the &lt;code&gt;Application.java&lt;/code&gt; file to try and start the app.&lt;br&gt;
This creates a run configuration for me. More often than not the app would not run for me.&lt;br&gt;
The errors would be singing a tune like&lt;br&gt;
&lt;code&gt;Could not instantiate a bean&lt;/code&gt;&lt;br&gt;
A spring boot application is all about following the beans.&lt;br&gt;
Looking at the bean one can see what properties it depends upon and try to correct the configurations.&lt;br&gt;
If the app depends on a DB or an instance of a message broker, start up a local version of the DB or message broker and point your app to the local instance.&lt;br&gt;
Eventually the app gets up and running.&lt;/p&gt;

&lt;h4&gt;
  
  
  Node.js Applications
&lt;/h4&gt;

&lt;p&gt;Look for the startup file specified in &lt;code&gt;package.json&lt;/code&gt;&lt;br&gt;
The convention is that it should be index.js.&lt;br&gt;
So I would run &lt;code&gt;node index.js&lt;/code&gt;.&lt;br&gt;
Again I follow the same process.&lt;br&gt;
There would be errors starting up the app and it is a matter of reading / deciphering the errors to find out what configurations / environment variables need to be tweaked to get the app running.&lt;/p&gt;

&lt;h4&gt;
  
  
  Golang Applications
&lt;/h4&gt;

&lt;p&gt;Look for &lt;code&gt;main.go&lt;/code&gt;&lt;br&gt;
If you have a &lt;code&gt;GoLand&lt;/code&gt; license, just click on the &lt;code&gt;Run&lt;/code&gt; next to the &lt;code&gt;main&lt;/code&gt; function.&lt;br&gt;
On command line run &lt;code&gt;go main.go&lt;/code&gt;&lt;br&gt;
Follow the process of deciphering the error messages and tweaking the configurations / environment variables to get the app running.&lt;/p&gt;

&lt;h4&gt;
  
  
  Docker
&lt;/h4&gt;

&lt;p&gt;Look out for the Dockerfile if one exists.&lt;br&gt;
If there is a Dockerfile, attempt to build the image and run it.&lt;br&gt;
The Dockerfile also provides clues on what environment variables need to be set.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's in it for me
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;You are not waiting on someone to walk through the code.&lt;/li&gt;
&lt;li&gt;There is a sense of achievement and satisfaction to get an app running.&lt;/li&gt;
&lt;li&gt;It validates my credentials as a Software Engineer&lt;/li&gt;
&lt;li&gt;It helps validate assumptions I had about the app or it helps understand things I did not know about the app.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Real life experience
&lt;/h2&gt;

&lt;p&gt;In my job as a tech lead, I joined a team that managed 20 or so microservices. It had a mix of &lt;code&gt;Java&lt;/code&gt; and &lt;code&gt;Node.js&lt;/code&gt;. It had a mix of &lt;code&gt;REST API&lt;/code&gt; and &lt;code&gt;Event Driven&lt;/code&gt; architectures. I had a choice, to wait on someone to walk me through them or do it by myself. I chose the latter and I understood the challenges the team was facing much better. It helped me in my ability to lead the team and make good architectural decisions.&lt;/p&gt;

</description>
      <category>microservices</category>
      <category>java</category>
      <category>node</category>
      <category>go</category>
    </item>
    <item>
      <title>Growing into a tech lead</title>
      <dc:creator>anandsunderraman</dc:creator>
      <pubDate>Fri, 09 Oct 2020 12:58:24 +0000</pubDate>
      <link>https://dev.to/anandsunderraman/growing-into-a-tech-lead-93g</link>
      <guid>https://dev.to/anandsunderraman/growing-into-a-tech-lead-93g</guid>
      <description>&lt;p&gt;Its almost 2 years since I assumed the role of a technical leader.&lt;br&gt;
I felt it would be a good time to reflect on my experiences and learnings.&lt;/p&gt;

&lt;h1&gt;
  
  
  Building Trust
&lt;/h1&gt;

&lt;p&gt;Growing into a tech lead role from a software engineering role was a different and challenging experience.&lt;br&gt;
Being promoted as a tech lead from within a team can be one experience, but joining as a tech lead of an already established team can be a different ball game altogether. My case was the latter where I joined as a tech lead for an already established team.&lt;br&gt;
So my first task was to build trust and the only way to build trust is to get to&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Observe how the team works&lt;/li&gt;
&lt;li&gt;Work along with the team to understand what they have to go through&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Investing time in best practices
&lt;/h1&gt;

&lt;p&gt;I take inspiration from cricket and best example of a leader is Mahendra Singh Dhoni.&lt;br&gt;
My observation has been that he has focussed on the process and the results just followed.&lt;br&gt;
Similarly in a software engineering team it is wise to invest time in best practices.&lt;br&gt;
Inculcating these practices and processes cannot happen overnight and can take long periods of time, sometimes even months because of other priorities.&lt;br&gt;
One just needs patience to pursue them and results will show over a period of time.&lt;/p&gt;

&lt;h1&gt;
  
  
  Collaboration
&lt;/h1&gt;

&lt;p&gt;Being a tech lead is a huge responsibility but that does not mean you have to have to know the ins and outs of everything.&lt;br&gt;
It is ok to say you don't know something and rely on advise from your team members to take the right decision.&lt;br&gt;
Your way need not be the HIGHWAY, a collaborative design has the following advantages&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Multiple diverse perspectives are accounted for.&lt;/li&gt;
&lt;li&gt;Rather than the tech lead owning the design, the team owns the design.&lt;/li&gt;
&lt;li&gt;Team know why certain decisions were taken during the design.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Enable your team
&lt;/h1&gt;

&lt;p&gt;You might not know every technology out there but your experience can help the team to look at the right direction.&lt;br&gt;
I am surprised many a times how I have not known anything about a technology but have been able to look at the right place just based on experience. Help team members with tips on troubleshooting.&lt;/p&gt;

&lt;h1&gt;
  
  
  Delegation
&lt;/h1&gt;

&lt;p&gt;There are times where I am overwhelmed with multiple things to do.&lt;br&gt;
I have made the mistake of taking it on all me and working overnight to get things done.&lt;br&gt;
But very recently I have taken a different approach.&lt;br&gt;
I make a list of things I need to do and then inspect if some of them can be delegated to folks in my team.&lt;br&gt;
It has dual benefits&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I am no longer overwhelmed&lt;/li&gt;
&lt;li&gt;The team also learns and grows.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Handling Stress
&lt;/h1&gt;

&lt;p&gt;Initially I would plan my day but then there would be unexpected issues that would derail my plans and I am always playing catch-up.&lt;br&gt;
There is no single solution to this predicament.&lt;br&gt;
All you can do is mentally be prepared for everything and then there is no stress at all !!&lt;br&gt;
I personally reflect on what are the "unexpected" issues and try to see if I can invest time in better processes or practices to avoid them in future.&lt;/p&gt;

&lt;h1&gt;
  
  
  Be Fearless
&lt;/h1&gt;

&lt;p&gt;Be fearless is another way of saying don't be afraid of failures. We all make mistakes. The important thing is to own it and take corrective action. I am lucky to be on a team where I am not penalized when I own a mistake. I believe a good leader is one who can talk about his/her failures so that others can learn from it. &lt;/p&gt;

&lt;h1&gt;
  
  
  Communication
&lt;/h1&gt;

&lt;p&gt;Communication is key, especially in times like these where we are remote.&lt;br&gt;
One rule of thumb I learnt early on was that if you find yourself typing huge paragraphs in a chat message it is time to get on a call to talk it out !!&lt;br&gt;
If your team needs to succeed you have to communicate clearly.&lt;br&gt;
When asking your team to work on a ticket or a story, explain to them why we need to work on it so that they have full context and are able to provide a better solution.&lt;/p&gt;

&lt;h1&gt;
  
  
  Learn
&lt;/h1&gt;

&lt;p&gt;Always be open to learn.&lt;br&gt;
Just because I am a tech lead does not mean I cannot learn from my junior team members. Many a times they are in the weeds of the problem and will come up with a better solution than you had imagined !!&lt;/p&gt;

&lt;p&gt;Continuing to learn and grow ...&lt;/p&gt;

</description>
      <category>leadership</category>
    </item>
    <item>
      <title>Running ELK (Elastic Logstash Kibana) on Docker</title>
      <dc:creator>anandsunderraman</dc:creator>
      <pubDate>Mon, 21 Sep 2020 03:50:04 +0000</pubDate>
      <link>https://dev.to/anandsunderraman/running-elk-elastic-logstash-kibana-on-docker-14he</link>
      <guid>https://dev.to/anandsunderraman/running-elk-elastic-logstash-kibana-on-docker-14he</guid>
      <description>&lt;p&gt;ELK (Elastic Logstash Kibana) are a set of software components that are part of the Elastic stack.&lt;/p&gt;

&lt;h1&gt;
  
  
  What does ELK do ?
&lt;/h1&gt;

&lt;p&gt;To explain in layman terms this what each of them do&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Elasticsearch&lt;/strong&gt; is primarily a data store&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logstash&lt;/strong&gt; is a data parsing software that stores the data in Elasticsearch in a desired format&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kibana&lt;/strong&gt; is the UI that can be used to query / visualize the data that is stored in Elasticsearch&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To get an in-depth understanding of what they do and how they work I would recommend &lt;a href="https://dev.to/lisahjung/beginner-s-guide-to-elasticsearch-4j2k"&gt;Beginner's Guide To Elastic Search&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  How do I run ELK ?
&lt;/h1&gt;

&lt;p&gt;Since each of the above components are separate pieces of software one way of running them is to head to the installation instructions and run each one of them separately. &lt;/p&gt;

&lt;p&gt;An easier and a more convenient way to run them would be using Docker.&lt;/p&gt;

&lt;p&gt;Most likely if you find yourself experimenting with this stack you would want to run all these 3 together. What better way to achieve than using &lt;code&gt;docker&lt;/code&gt; and &lt;code&gt;docker-compose&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Docker Compose
&lt;/h2&gt;

&lt;p&gt;At the time of writing this post I was experimenting with ELK stack version &lt;code&gt;6.6&lt;/code&gt;. Hence the following &lt;code&gt;docker-compose.yml&lt;/code&gt; refers to image versions &lt;code&gt;6.6&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;If you notice the above gist it references a directory by name &lt;code&gt;logstash-conf&lt;/code&gt;. The contents of this directory is a &lt;code&gt;logstash&lt;/code&gt; configuration file that dictates how the data needs to be parsed.&lt;/p&gt;

&lt;p&gt;The contents of this file would be:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  What are we configuring in Logstash ?
&lt;/h3&gt;

&lt;p&gt;The following section says we will get the input for logstash via &lt;code&gt;beats&lt;/code&gt; which is another software in &lt;code&gt;Elastic&lt;/code&gt; which I will attempt to explain in another post.&lt;/p&gt;

&lt;p&gt;We configure to obtain data via port &lt;code&gt;5044&lt;/code&gt; and we expect the data to be in &lt;code&gt;json&lt;/code&gt; format&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;input {
    beats {
        port =&amp;gt; "5044"
        codec =&amp;gt; "json"
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we state that we are using the &lt;code&gt;json&lt;/code&gt; plugin in logstash and attempt to extract &lt;code&gt;json&lt;/code&gt; data from the &lt;code&gt;message&lt;/code&gt; field in our log message. I know this sounds a bit cryptic but hope you take the leap of faith with me on this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;filter {
  json {
    source =&amp;gt; "message"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally we have the output. We basically are passing on the data to elasticsearch to store the data in an index that is defined by &lt;code&gt;"%{[fields][project]}-%{[fields][application]}-%{+YYYY.MM.dd}"&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;output {
    elasticsearch {
        hosts =&amp;gt; "${ELASTIC_HOST}"
        index =&amp;gt; "%{[fields][project]}-%{[fields][application]}-%{+YYYY.MM.dd}"
        codec =&amp;gt; json
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How to run it ?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Start &lt;code&gt;docker&lt;/code&gt; on your local machine&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;docker-compose up&lt;/code&gt; in the directory where you have the &lt;code&gt;docker-compose.yml&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How do I navigate to Kibana ?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Point your browser to &lt;code&gt;http://localhost:5601/&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;Note this is based on the port &lt;code&gt;5601&lt;/code&gt; provided for the &lt;code&gt;kibana&lt;/code&gt; image on the &lt;code&gt;docker-compose.yml&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;The main goal of this tutorial was to demonstrate how to get the ELK stack running using docker&lt;/p&gt;

</description>
      <category>docker</category>
    </item>
    <item>
      <title>JSON Logging in Spring Boot Applications</title>
      <dc:creator>anandsunderraman</dc:creator>
      <pubDate>Fri, 18 Sep 2020 02:28:48 +0000</pubDate>
      <link>https://dev.to/anandsunderraman/json-logging-in-spring-boot-applications-2j33</link>
      <guid>https://dev.to/anandsunderraman/json-logging-in-spring-boot-applications-2j33</guid>
      <description>&lt;p&gt;Application logs are like the black box. When troubleshooting issues first thing I look at is the application logs. It becomes essential to put thought into what we log in order to be able to identify issues based on logs.&lt;/p&gt;

&lt;p&gt;Today we have a class of applications called log aggregation systems. Log aggregation is useful when we have lot of microservices and we want to trace logs across microservices.&lt;/p&gt;

&lt;p&gt;I would like to demonstrate how to log application logs in a JSON format.&lt;/p&gt;

&lt;h1&gt;
  
  
  Advantages of JSON Logging
&lt;/h1&gt;

&lt;p&gt;A traditional java application log would look something like the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2020-09-17 21:56:10.740  INFO [Orders:restartedMain::] o.s.b.w.embedded.tomcat.TomcatWebServer - Tomcat started on port(s): 8080 (http) with context path ''
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If one were to search it in a unix box one would do a&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat application.log | grep &amp;lt;your-search&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I recall days where logs like these were shipped by me to Sumo Logic (another log aggregation system) and I would use regular expression gymnastics to arrive at an optimal search.&lt;/p&gt;

&lt;p&gt;Someone came up with this different approach of why not store the logs in a more searchable format when it is primarily used for searching. JSON happened to lend itself easily to being searched and hence json logging. Another way to refer to this is also structured logs, because the logs have a well defined structure which can later be used to search.&lt;/p&gt;

&lt;p&gt;The same application log displayed above in a JSON format would look like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "@timestamp": "2020-06-17T14:41:11.174-04:00",
  "@version": "1",
  "message": "Tomcat initialized with port(s): 8080 (http)",
  "logger_name": "org.springframework.boot.web.embedded.tomcat.TomcatWebServer",
  "thread_name": "restartedMain",
  "level": "INFO",
  "level_value": 20000
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This now makes it easier to search the logs by say &lt;code&gt;time&lt;/code&gt; or &lt;code&gt;level&lt;/code&gt; or even &lt;code&gt;thread_name&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  JSON Logging in Spring Boot Application
&lt;/h1&gt;

&lt;p&gt;For logging logs in a JSON format one needs to include 2 dependencies. If you use maven for dependency management one would include the dependencies as follows&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;net.logstash.logback&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;logstash-logback-encoder&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;6.4&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;ch.qos.logback&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;logback-classic&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;1.2.3&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we are using the library &lt;a href="https://github.com/logstash/logstash-logback-encoder"&gt;logstash-logback-encoder&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can then configure the json encoder the logback with the following code snippet&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;encoder class="net.logstash.logback.encoder.LogstashEncoder"&amp;gt;
    &amp;lt;providers&amp;gt;
        &amp;lt;timestamp&amp;gt;
            &amp;lt;timeZone&amp;gt;EST&amp;lt;/timeZone&amp;gt;
        &amp;lt;/timestamp&amp;gt;
        &amp;lt;pattern&amp;gt;
            &amp;lt;pattern&amp;gt;
                {
                "level": "%level",
                "service": "orders",
                "traceId": "%X{X-B3-TraceId:-}",
                "spanId": "%X{X-B3-SpanId:-}",
                "thread": "%thread",
                "class": "%logger{40}",
                "message": "%message"
                }
            &amp;lt;/pattern&amp;gt;
        &amp;lt;/pattern&amp;gt;
        &amp;lt;stackTrace&amp;gt;
            &amp;lt;throwableConverter class="net.logstash.logback.stacktrace.ShortenedThrowableConverter"&amp;gt;
                &amp;lt;maxDepthPerThrowable&amp;gt;30&amp;lt;/maxDepthPerThrowable&amp;gt;
                &amp;lt;maxLength&amp;gt;2048&amp;lt;/maxLength&amp;gt;
                &amp;lt;shortenedClassNameLength&amp;gt;20&amp;lt;/shortenedClassNameLength&amp;gt;
                &amp;lt;rootCauseFirst&amp;gt;true&amp;lt;/rootCauseFirst&amp;gt;
            &amp;lt;/throwableConverter&amp;gt;
        &amp;lt;/stackTrace&amp;gt;
    &amp;lt;/providers&amp;gt;
&amp;lt;/encoder&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So let us assume you want to log the data as traditional logs to the console and log them as json to a file we can configure the logback xml as follows&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;
&amp;lt;configuration&amp;gt;
    &amp;lt;include resource="org/springframework/boot/logging/logback/console.xml"/&amp;gt;
    &amp;lt;appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"&amp;gt;
        &amp;lt;encoder&amp;gt;
            &amp;lt;pattern&amp;gt;%d{yyyy-MM-dd HH:mm:ss.SSS} %5p [Orders:%thread:%X{X-B3-TraceId}:%X{X-B3-SpanId}] %logger{40} - %msg%n
            &amp;lt;/pattern&amp;gt;
        &amp;lt;/encoder&amp;gt;
    &amp;lt;/appender&amp;gt;
    &amp;lt;appender name="fileout"
              class="ch.qos.logback.core.rolling.RollingFileAppender"&amp;gt;
        &amp;lt;File&amp;gt;./logs/orders.log&amp;lt;/File&amp;gt;
        &amp;lt;rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"&amp;gt;
            &amp;lt;maxIndex&amp;gt;8&amp;lt;/maxIndex&amp;gt;
            &amp;lt;FileNamePattern&amp;gt;./logs/orders.log.%i
            &amp;lt;/FileNamePattern&amp;gt;
        &amp;lt;/rollingPolicy&amp;gt;
        &amp;lt;triggeringPolicy
                class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"&amp;gt;
            &amp;lt;MaxFileSize&amp;gt;128MB&amp;lt;/MaxFileSize&amp;gt;
        &amp;lt;/triggeringPolicy&amp;gt;

        &amp;lt;encoder class="net.logstash.logback.encoder.LogstashEncoder"&amp;gt;
            &amp;lt;providers&amp;gt;
                &amp;lt;timestamp&amp;gt;
                    &amp;lt;timeZone&amp;gt;EST&amp;lt;/timeZone&amp;gt;
                &amp;lt;/timestamp&amp;gt;
                &amp;lt;pattern&amp;gt;
                    &amp;lt;pattern&amp;gt;
                        {
                        "level": "%level",
                        "service": "orders",
                        "traceId": "%X{X-B3-TraceId:-}",
                        "spanId": "%X{X-B3-SpanId:-}",
                        "thread": "%thread",
                        "class": "%logger{40}",
                        "message": "%message"
                        }
                    &amp;lt;/pattern&amp;gt;
                &amp;lt;/pattern&amp;gt;
                &amp;lt;stackTrace&amp;gt;
                    &amp;lt;throwableConverter class="net.logstash.logback.stacktrace.ShortenedThrowableConverter"&amp;gt;
                        &amp;lt;maxDepthPerThrowable&amp;gt;30&amp;lt;/maxDepthPerThrowable&amp;gt;
                        &amp;lt;maxLength&amp;gt;2048&amp;lt;/maxLength&amp;gt;
                        &amp;lt;shortenedClassNameLength&amp;gt;20&amp;lt;/shortenedClassNameLength&amp;gt;
                        &amp;lt;rootCauseFirst&amp;gt;true&amp;lt;/rootCauseFirst&amp;gt;
                    &amp;lt;/throwableConverter&amp;gt;
                &amp;lt;/stackTrace&amp;gt;
            &amp;lt;/providers&amp;gt;
        &amp;lt;/encoder&amp;gt;
    &amp;lt;/appender&amp;gt;
    &amp;lt;root level="info"&amp;gt;
        &amp;lt;appender-ref ref="fileout" /&amp;gt;
        &amp;lt;appender-ref ref="stdout" /&amp;gt;
    &amp;lt;/root&amp;gt;
&amp;lt;/configuration&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a complete spring boot application with json logging please refer to sample applications &lt;a href="https://github.com/anandsunderraman/structured-logging-tutorial/tree/master/orders"&gt;orders&lt;/a&gt; or &lt;a href="https://github.com/anandsunderraman/structured-logging-tutorial/tree/master/shipping"&gt;shipping&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;JSON logging can be achieved in other languages / frameworks as well like node.js and python.&lt;/p&gt;

&lt;p&gt;For node.js libraries like &lt;a href="https://github.com/winstonjs/winston"&gt;winston&lt;/a&gt; can be used.&lt;/p&gt;

</description>
      <category>microservices</category>
      <category>java</category>
    </item>
    <item>
      <title>Copying over data from MongoDB to S3</title>
      <dc:creator>anandsunderraman</dc:creator>
      <pubDate>Sat, 25 Apr 2020 03:35:21 +0000</pubDate>
      <link>https://dev.to/anandsunderraman/copying-over-data-from-mongodb-to-s3-3j4g</link>
      <guid>https://dev.to/anandsunderraman/copying-over-data-from-mongodb-to-s3-3j4g</guid>
      <description>&lt;h1&gt;
  
  
  Copying over data from MongoDB to S3
&lt;/h1&gt;

&lt;p&gt;Very recently we were tasked with copying over data from our MongoDB DB to an S3 bucket.&lt;br&gt;
Since the timelines were tight our immediate solution to this was deploy a lambda that will run once a day, query data from MongoDB and copy it to s3.&lt;/p&gt;

&lt;p&gt;We sized up the data to be around 600k records. It did not seem like a lot and we were confident of achieving the same.&lt;/p&gt;

&lt;p&gt;Long story short this turned out to be a bigger task than we thought and we ran into multiple problems.&lt;/p&gt;

&lt;p&gt;I would like to talk about the problems we faced at each stage and how we improvised and finally arrived at a working solution.&lt;/p&gt;

&lt;p&gt;At the end of the process I learnt a lot but I learnt that I have lots more to learn.&lt;/p&gt;

&lt;p&gt;Ok getting down to details.&lt;/p&gt;
&lt;h2&gt;
  
  
  Tech Stack
&lt;/h2&gt;

&lt;p&gt;AWS Lambda on Node.js 12.x&lt;/p&gt;
&lt;h2&gt;
  
  
  First Attempt
&lt;/h2&gt;

&lt;p&gt;Our first attempt was a brute force attempt in hindsight. &lt;/p&gt;
&lt;h3&gt;
  
  
  The approach was:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Query the collection asynchronously in batches of 100k&lt;/li&gt;
&lt;li&gt;Do a Promise.all on all the batches of queries&lt;/li&gt;
&lt;li&gt;Concatenate the results array&lt;/li&gt;
&lt;li&gt;Write the data to a s3 file&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Outcome:
&lt;/h3&gt;

&lt;p&gt;Since we tried to load all the 600k records into a string to put an object into s3 we ran out of memory even after allocating the maximum permissible memory 3008MB&lt;/p&gt;
&lt;h3&gt;
  
  
  Code:
&lt;/h3&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Second Attempt
&lt;/h2&gt;

&lt;p&gt;Based on our first attempt it was clear we had to handle our arrays carefully. &lt;br&gt;
In the first attempt we first flattened the results array into a single array.&lt;br&gt;
We then iterated over the flatenned array and transformed each db record into a string and then push it into another array and hence the memory was insufficient&lt;/p&gt;
&lt;h3&gt;
  
  
  The approach was:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Do the array flatenning and transforming it to strings in a single array&lt;/li&gt;
&lt;li&gt;Write the data to a s3 file&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Outcome:
&lt;/h3&gt;

&lt;p&gt;Success !! we finally were able to write all the records to a s3 file&lt;br&gt;
The issue was we used up all the 3008MB. So although it works for the current scenario, it is not future proof and we might run into memory issues again&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DwRaC-aI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/f3wdc1hr72hnbgf94l54.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DwRaC-aI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/f3wdc1hr72hnbgf94l54.png" alt="Using up all the memory" width="880" height="35"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Code:
&lt;/h3&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Third Attempt
&lt;/h2&gt;

&lt;p&gt;So although from the previous attempt we tasted success we need  a more efficient way to handle these huge arrays of data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Streams
&lt;/h3&gt;

&lt;p&gt;A little google search and stackoverflow questions led me to streams in node.js&lt;br&gt;
I will not delve deep into streams but rather quote resources that I referred to.&lt;br&gt;
The main concept of streams is that when you have large amounts of data to work with, rather than loading it all in memory, just load smaller chunks of it and work with it.&lt;br&gt;
On digging deeper we found that mongodb find and aggregate operations by default return streams.&lt;br&gt;
We also found that s3 upload api accepted a readable stream and had the ability to do a multipart upload. This seemed like a perfect way to work.&lt;br&gt;
Mongodb query results would be the data source and s3 file would be the sink.&lt;/p&gt;
&lt;h3&gt;
  
  
  The approach was:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Stream the mongodb results&lt;/li&gt;
&lt;li&gt;Mongodb aggregate default cursor size streams 16MB worth of data&lt;/li&gt;
&lt;li&gt;Use s3 multipart upload api&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Outcome:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Even more success !!. We managed to reduce the memory consumption from 3008MB to 200 - 300MB. That was a huge win for us.&lt;/li&gt;
&lt;li&gt;The issue was that there was some code issue because of which the node script would not exit and the lambda would timeout after the max time of 900 seconds even though the actual execution was completed way before
Due to the timeout issue the lambda retries 3 times and so the file is written 3 times, wasted executions&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CSiumskb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/gzr2iixsqkl9nv7rgdz2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CSiumskb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/gzr2iixsqkl9nv7rgdz2.png" alt="Reduced memory consumption" width="880" height="438"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Code:
&lt;/h3&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Fourth Attempt
&lt;/h2&gt;

&lt;p&gt;We had nailed down most of the approach and the question was how to exit the node.js function. We realized we did not call the callback function of the lambda handler once the upload was done. Once that was done we were able to complete the execution under 490 seconds and exit the function.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LsZfDJZ9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2fyvrieq9wtgauiph75z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LsZfDJZ9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2fyvrieq9wtgauiph75z.png" alt="Lambda exits before timeout" width="880" height="162"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Code:
&lt;/h3&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


</description>
      <category>node</category>
      <category>streams</category>
      <category>s3</category>
      <category>aws</category>
    </item>
  </channel>
</rss>
