<?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: Gauthier POGAM--LE MONTAGNER</title>
    <description>The latest articles on DEV Community by Gauthier POGAM--LE MONTAGNER (@gauthierplm).</description>
    <link>https://dev.to/gauthierplm</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%2F386154%2F710d0144-69c4-4228-8af9-a6162205d963.jpeg</url>
      <title>DEV Community: Gauthier POGAM--LE MONTAGNER</title>
      <link>https://dev.to/gauthierplm</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gauthierplm"/>
    <language>en</language>
    <item>
      <title>Use Coolify to self-host SigNoz</title>
      <dc:creator>Gauthier POGAM--LE MONTAGNER</dc:creator>
      <pubDate>Wed, 10 Sep 2025 08:38:57 +0000</pubDate>
      <link>https://dev.to/gauthierplm/use-coolify-to-self-host-signoz-1h6b</link>
      <guid>https://dev.to/gauthierplm/use-coolify-to-self-host-signoz-1h6b</guid>
      <description>&lt;p&gt;Observability can be a tricky subject requiring a lot of dedication to do it properly. And one thing we don't want is to spend hours deploying the required services before even starting to integrate observability in our ecosystem.&lt;/p&gt;

&lt;p&gt;Luckily for us, &lt;a href="https://coolify.io/" rel="noopener noreferrer"&gt;Coolify&lt;/a&gt; now have a template to easily deploy &lt;a href="https://signoz.io/" rel="noopener noreferrer"&gt;SigNoz&lt;/a&gt;, an open source observability platform. This guide will go through the steps to set it up in Coolify.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding the service
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Update: the template has been merged in Coolify. You can now find it in the list of Coolify' services.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At the moment of writing, SigNoz' template is still in PR. To add it to your Coolify:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Copy the content of &lt;code&gt;signoz.yaml&lt;/code&gt; from the &lt;a href="https://github.com/coollabsio/coolify/pull/5386" rel="noopener noreferrer"&gt;PR&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;In Coolify, create a new Docker Compose service and select the server to host it.&lt;/li&gt;
&lt;li&gt;Paste the content of &lt;code&gt;signoz.yaml&lt;/code&gt; in the "Docker Compose file" field.&lt;/li&gt;
&lt;li&gt;Rename the service name to &lt;code&gt;SigNoz&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  URLs configuration
&lt;/h2&gt;

&lt;p&gt;Once created, you are ready to set the URLs you'll use with SigNoz.&lt;/p&gt;

&lt;p&gt;First, update the URL of the signoz container. For example: &lt;code&gt;https://signoz.example.com:8080&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then, let's configure the Otel Collector. This service collects the traces, metrics and logs from your applications and services and supports many different formats: OTel' GRPC and HTTP formats, Prometheus metrics, and &lt;a href="https://signoz.io/docs/userguide/logs/" rel="noopener noreferrer"&gt;many logs formats&lt;/a&gt; (FluentBit/FluentD, syslogs, logs from cloud services, ...).&lt;/p&gt;

&lt;p&gt;Each format should be received on a different port, which we will need to expose for the OTel Coollector to be accessible. You have two strategies to do so:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configuring a domain for each receiver, or...&lt;/li&gt;
&lt;li&gt;Directly exposing the ports to the host and the outside world.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Which option you prefers depends on you security needs and how you architecture your domains.&lt;/p&gt;

&lt;h3&gt;
  
  
  One subdomain per receiver
&lt;/h3&gt;

&lt;p&gt;This solution only requires you to map your subdomain to the Otel Collector service. We will cover the two default receivers, the HTTP and GRPC receivers.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Make sure your subdomains have been registered and point to your server. In my case, I chose &lt;code&gt;https://signoz-grpc.example.com&lt;/code&gt; and &lt;code&gt;https://signoz-http.example.com&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Open the "Otel Collector" service settings.&lt;/li&gt;
&lt;li&gt;Add your domains with the format &lt;code&gt;https://&amp;lt;subdomain&amp;gt;.example.com:&amp;lt;port in container&amp;gt;&lt;/code&gt;, separated by commas.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For example, this is what I have setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://signoz-grpc.example.com:4317,https://signoz-http.example.com:4318
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to &lt;a href="https://signoz.io/docs/userguide/heroku_logs_to_signoz/" rel="noopener noreferrer"&gt;drain logs from Heroku&lt;/a&gt;, you can add a subdomain to receive the logs: &lt;code&gt;...,https://signoz-heroku.example.com:8081&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exposing the ports on the host
&lt;/h3&gt;

&lt;p&gt;If you prefer to use a single domain for all receivers, you can edit the Docker Compose to directly expose the ports on the otel-collector container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;span class="na"&gt;otel-collector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;signoz/signoz-otel-collector:latest&lt;/span&gt;
  &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;signoz-otel-collector&lt;/span&gt;
  &lt;span class="c1"&gt;# ...&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;4317:4317&lt;/span&gt; &lt;span class="c1"&gt;# GRPC Collector&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;4318:4318&lt;/span&gt; &lt;span class="c1"&gt;# HTTP Collector&lt;/span&gt;

  &lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now append the port to your service URL to send data to receiver: &lt;code&gt;https://signoz.example.com:4318&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Fixing the health checks
&lt;/h2&gt;

&lt;p&gt;If you tried to run the services, you should have noticed Coolify keeps reporting SigNoz as unhealthy. This is because some containers exit after performing their task, causing Coolify to consider them unhealthy.&lt;/p&gt;

&lt;p&gt;To have Coolify properly reporting the health status, you will need to exclude &lt;code&gt;Schema Migrator Sync&lt;/code&gt;, &lt;code&gt;Schema Migrator Async&lt;/code&gt; and &lt;code&gt;Init Clickhouse&lt;/code&gt; from the healthcheck.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the settings of the service.&lt;/li&gt;
&lt;li&gt;Check &lt;code&gt;Exclude from service status&lt;/code&gt; and save the settings.&lt;/li&gt;
&lt;li&gt;When you excluded the three services, you can now (re)deploy all  SigNoz services for the health check to ignore these three containers.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Enabling SMTP emailing
&lt;/h2&gt;

&lt;p&gt;SigNoz uses emailing for two things: inviting users and to &lt;a href="https://signoz.io/docs/alerts/" rel="noopener noreferrer"&gt;send alerts&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  SigNoz emails
&lt;/h3&gt;

&lt;p&gt;To enable SMTP emailing (including inviting new team members), you need to set the following variables from the Environment Variables tab of your Coolify service:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;SIGNOZ_EMAILING_ENABLED&lt;/code&gt; enables emailing capabilities in SigNoz.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SIGNOZ_EMAILING_SMTP_ADDRESS&lt;/code&gt; is the address of the SMTP server to use, in the format &lt;code&gt;host:port&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SIGNOZ_EMAILING_SMTP_FROM&lt;/code&gt; is the email address to use in the From field.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SIGNOZ_EMAILING_SMTP_AUTH_USERNAME&lt;/code&gt; and &lt;code&gt;SIGNOZ_EMAILING_SMTP_AUTH_PASSWORD&lt;/code&gt; are used to authenticate with the SMTP server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More environment variables are &lt;a href="https://signoz.io/docs/manage/administrator-guide/configuration/smtp-email-invitations/" rel="noopener noreferrer"&gt;available to use&lt;/a&gt; to use authenticate via Identity / Secret or use TLS instead of SmartTLS. Read &lt;a href="https://dev.topassing-environment-variables-not-included-in-the-template"&gt;Passing environment variables not included in the template&lt;/a&gt; to learn how to add them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Alert Manager emails
&lt;/h3&gt;

&lt;p&gt;Email alerts can only be sent if an SMTP server is configured specifically for the alert manager. The global SMTP configuration and the Alert Manager configuration use different environment variables.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: SigNoz has a current known issue preventing email alerting configuration from being saved. You can track the progress of this &lt;a href="https://github.com/SigNoz/signoz/issues/8478" rel="noopener noreferrer"&gt;issue in their bug tracker&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To enable email alerts, you need to set the following variables from the Environment Variables tab of your Coolify service:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;SIGNOZ_ALERTMANAGER_SIGNOZ_GLOBAL_SMTP__SMARTHOST&lt;/code&gt; is the address of the SMTP server to use, in the format &lt;code&gt;host:port&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SIGNOZ_ALERTMANAGER_SIGNOZ_GLOBAL_SMTP__FROM&lt;/code&gt; is the email address to use in the From field.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SIGNOZ_ALERTMANAGER_SIGNOZ_GLOBAL_SMTP__AUTH__USERNAME&lt;/code&gt; and &lt;code&gt;SIGNOZ_ALERTMANAGER_SIGNOZ_GLOBAL_SMTP__AUTH__PASSWORD&lt;/code&gt; are used to authenticate with the SMTP server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More environment variables are &lt;a href="https://signoz.io/docs/manage/administrator-guide/configuration/alertmanager/" rel="noopener noreferrer"&gt;available to use&lt;/a&gt; to use authenticate via Identity / Secret or use TLS instead of SmartTLS. Read &lt;a href="https://dev.topassing-environment-variables-not-included-in-the-template"&gt;Passing environment variables not included in the template&lt;/a&gt; to learn how to add them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Passing environment variables not included in the template
&lt;/h2&gt;

&lt;p&gt;You may want to define environment variables that are not included in SigNoz' template (for example new TLS settings for the SMTP / Alert Manager email configuration). Luckily, Coolify makes this process pretty simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Edit the Docker Compose in Coolify.&lt;/li&gt;
&lt;li&gt;Add the desired variables to the &lt;code&gt;environment&lt;/code&gt; of the &lt;code&gt;signoz&lt;/code&gt; container with the following format: &lt;code&gt;- &amp;lt;VARIABLE_NAME&amp;gt;=${&amp;lt;VARIABLE_NAME&amp;gt;}&lt;/code&gt;. For example: &lt;code&gt;SIGNOZ_EMAILING_SMTP_FROM=${SIGNOZ_EMAILING_SMTP_FROM}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Go in the Environment Variables tab of you Coolify service and set the value of the newly added variables.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Updating SigNoz
&lt;/h2&gt;

&lt;p&gt;To update SigNoz to a more recent version, you just need to pull the latest version in Coolify.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the service in Coolify&lt;/li&gt;
&lt;li&gt;Top right of the screen, click on "Advanced" and select "Pull Latest Images and Restart".&lt;/li&gt;
&lt;li&gt;Wait for the migration and full restart of SigNoz (can take a few minutes).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkvvy0w9gm8gre5elik3v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkvvy0w9gm8gre5elik3v.png" alt=" " width="362" height="143"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;SigNoz is now setup and ready to accept logs and traces from your applications and infrastructure.&lt;/p&gt;

&lt;p&gt;Their &lt;a href="https://signoz.io/docs/introduction/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; is a good start to learn how to onboard your resources. &lt;a href="https://opentelemetry.io/" rel="noopener noreferrer"&gt;OpenTelemetry&lt;/a&gt; documentation is also a reference, containing the recommended steps to best leverage the OpenTelemetry SDKs and tools for your stack.&lt;/p&gt;

&lt;p&gt;Did you find any way to improve the Coolify template, SigNoz setup, or want to suggest a change? Feel free to let me know! I'd be very happy to learn how to make SigNoz even more pleasant to use.&lt;/p&gt;

</description>
      <category>observability</category>
      <category>selfhosting</category>
      <category>coolify</category>
      <category>signoz</category>
    </item>
    <item>
      <title>Office365: make a Room Calendar visible for all employees</title>
      <dc:creator>Gauthier POGAM--LE MONTAGNER</dc:creator>
      <pubDate>Tue, 01 Apr 2025 12:56:48 +0000</pubDate>
      <link>https://dev.to/gauthierplm/office365-make-a-room-calendar-visible-for-all-employees-190o</link>
      <guid>https://dev.to/gauthierplm/office365-make-a-room-calendar-visible-for-all-employees-190o</guid>
      <description>&lt;p&gt;After creating a &lt;a href="https://learn.microsoft.com/en-us/microsoft-365/admin/manage/room-and-equipment-mailboxes?view=o365-worldwide" rel="noopener noreferrer"&gt;Room mailbox in Microsoft Admin Center&lt;/a&gt;, you may want to make  the room' calendar visible for everyone in your organization. However, Microsoft does not expose any settings to do it from the UI.&lt;/p&gt;

&lt;p&gt;The solution is to use Powershell to edit the calendar access permission.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install the ExchangeOnlineManagement module if you don't have it&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Install-Module&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ExchangeOnlineManagement&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Open a session from Powershell&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Connect-ExchangeOnline&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-UserPrincipalName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;YOU_ADMIN_USERNAME&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ShowProgress&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$true&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Grant everyone access to the mailbox by setting the default permission&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Set-MailboxFolderPermission&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Identity&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;ROOM_MAILBOX_EMAIL&amp;gt;:\Calendar"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-User&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Default&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-AccessRights&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Reviewer&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Check the permissions&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Get-MailboxFolderPermission&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Identity&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;ROOM_MAILBOX_EMAIL&amp;gt;:\Calendar"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Disconnect from the session&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Disconnect-ExchangeOnline&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Confirm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="bp"&gt;$false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, go in your Outlook client (desktop / mobile / web) and &lt;a href="https://support.microsoft.com/en-us/office/open-another-person-s-exchange-calendar-2257f515-408f-48ea-9363-11d0d5848c77" rel="noopener noreferrer"&gt;add a coworker calendar&lt;/a&gt;. You should now be able to find the Room' calendar and see who booked what.&lt;/p&gt;

</description>
      <category>office365</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Maven Resource Filtering: injecting POM' properties in your resources</title>
      <dc:creator>Gauthier POGAM--LE MONTAGNER</dc:creator>
      <pubDate>Sat, 17 Sep 2022 16:43:31 +0000</pubDate>
      <link>https://dev.to/gauthierplm/maven-resource-filtering-injecting-pom-properties-in-your-resources-2pba</link>
      <guid>https://dev.to/gauthierplm/maven-resource-filtering-injecting-pom-properties-in-your-resources-2pba</guid>
      <description>&lt;p&gt;In my previous blog post &lt;a href="https://dev.to/gauthierplm/how-to-output-log4j2-logs-as-json-5an3"&gt;How to output Log4J2 logs as JSON?&lt;/a&gt;, I mentioned that we can extract some properties from our project' &lt;code&gt;pom.xml&lt;/code&gt; to add them to our logs. This can be done using Maven' &lt;a href="https://maven.apache.org/plugins/maven-resources-plugin/index.html" rel="noopener noreferrer"&gt;&lt;code&gt;maven-resource-plugin&lt;/code&gt;&lt;/a&gt; and its filtering capabilities.&lt;/p&gt;

&lt;p&gt;I will explain what is resource filtering, how it can be configured, and how to apply this to extract properties from a &lt;code&gt;pom.xml&lt;/code&gt; to inject them into a &lt;code&gt;log4j2.xml&lt;/code&gt; configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is resource filtering?
&lt;/h2&gt;

&lt;p&gt;Before compiling the source or your tests, the resources of your application are copied from your project' resource folder (&lt;code&gt;src/main/resources&lt;/code&gt;) to Maven' target folder. Maven automatically copies these resources using &lt;a href="https://maven.apache.org/plugins/maven-resources-plugin/index.html" rel="noopener noreferrer"&gt;&lt;code&gt;maven-resource-plugin&lt;/code&gt;&lt;/a&gt;, one of Maven' standard plugins, called by most goals that require it (such as &lt;code&gt;compile&lt;/code&gt; or &lt;code&gt;test-compile&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;These resources are any file that your application will use but that should not be compiled, such as properties files, assets, TLS certificates,... Most applications have at least one resource file: a logger configuration file like Log4J2' log4j2.xml file.&lt;/p&gt;

&lt;p&gt;When building your project, you might want these files to contain some of the many properties defined in your pom.xml, such as your application' name, version, or one of the properties defined in your pom.xml. By default, however, Maven won't apply any change to your resources. You will have to configure it to injects the properties you want in your resources files. Injecting properties in your resources is what we call &lt;strong&gt;filtering the resources&lt;/strong&gt; of your project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enabling resource filtering
&lt;/h2&gt;

&lt;p&gt;To filter your resources, you must tell Maven which files it should filter, and in these files you should define the variables Maven should replace.&lt;/p&gt;

&lt;p&gt;Enabling filtering in Maven is pretty simple: you just have to enable it in the configuration of your application resources. This can be done by editing the &lt;code&gt;resource&lt;/code&gt; tag in the build section of your application to add the property &lt;code&gt;&amp;lt;filtering&amp;gt;true&amp;lt;/filtering&amp;gt;&lt;/code&gt; to your resources configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;project&amp;gt;&lt;/span&gt;
  ...
  &lt;span class="nt"&gt;&amp;lt;build&amp;gt;&lt;/span&gt;
    ...
    &lt;span class="nt"&gt;&amp;lt;resources&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;resource&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;directory&amp;gt;&lt;/span&gt;src/main/resources&lt;span class="nt"&gt;&amp;lt;/directory&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;filtering&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/filtering&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/resource&amp;gt;&lt;/span&gt;
      ...
    &lt;span class="nt"&gt;&amp;lt;/resources&amp;gt;&lt;/span&gt;
    ...
  &lt;span class="nt"&gt;&amp;lt;/build&amp;gt;&lt;/span&gt;
  ...
&lt;span class="nt"&gt;&amp;lt;/project&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once enabled, every resources in &lt;code&gt;src/main/resources&lt;/code&gt; will be filtered. Therefore, we can now use filtering to replace variables in our resource files. Let's create a file &lt;code&gt;test.txt&lt;/code&gt; and add the following content in it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Hello, I am project ${project.name}, version ${project.version}. You can identify me by my full name ${project.groupId}:${project.artifactId}.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now run the command &lt;code&gt;mvn compile&lt;/code&gt; and open &lt;code&gt;target/classes/test.txt&lt;/code&gt;. You will find the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Hello, I am project my-test-app, version 1.0.0-SNAPSHOT. You can identify me by my full name com.company.dev:my-test-app.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Filter specific files
&lt;/h3&gt;

&lt;p&gt;By default, filtering applies to every files in your resources that are not binary files (like images). To avoid replacing content that use the same syntax as a property but which should not be replaced, it is recommended to manually select which files are filtered and exclude everything else.&lt;/p&gt;

&lt;p&gt;Fortunately, Maven makes it very simple to configure which resources should be filtered by using the &lt;code&gt;&amp;lt;includes&amp;gt;&lt;/code&gt; tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;project&amp;gt;&lt;/span&gt;
  ...
  &lt;span class="nt"&gt;&amp;lt;build&amp;gt;&lt;/span&gt;
    ...
    &lt;span class="nt"&gt;&amp;lt;resources&amp;gt;&lt;/span&gt;
      &lt;span class="c"&gt;&amp;lt;!-- Enable filtering for specific resources --&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;resource&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;directory&amp;gt;&lt;/span&gt;src/main/resources&lt;span class="nt"&gt;&amp;lt;/directory&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;filtering&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/filtering&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;includes&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;include&amp;gt;&lt;/span&gt;test.txt&lt;span class="nt"&gt;&amp;lt;/include&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/includes&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/resource&amp;gt;&lt;/span&gt;
      &lt;span class="c"&gt;&amp;lt;!-- Disable filtering for everything else.
           This part is necessary so Maven continues to copy non-filtered resources.
      --&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;resource&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;directory&amp;gt;&lt;/span&gt;src/main/resources&lt;span class="nt"&gt;&amp;lt;/directory&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;filtering&amp;gt;&lt;/span&gt;false&lt;span class="nt"&gt;&amp;lt;/filtering&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;excludes&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;exclude&amp;gt;&lt;/span&gt;test.txt&lt;span class="nt"&gt;&amp;lt;/exclude&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/excludes&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/resource&amp;gt;&lt;/span&gt;
      ...
    &lt;span class="nt"&gt;&amp;lt;/resources&amp;gt;&lt;/span&gt;
    ...
  &lt;span class="nt"&gt;&amp;lt;/build&amp;gt;&lt;/span&gt;
  ...
&lt;span class="nt"&gt;&amp;lt;/project&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will note that we added the &lt;code&gt;&amp;lt;resource&amp;gt;&lt;/code&gt; tag twice: one with filtering enabled, and a second time without it. If we only added the first tag with the &lt;code&gt;&amp;lt;includes&amp;gt;&lt;/code&gt; configured, Maven would only copy (and filter) the resources included in this configuration (in our case, only &lt;code&gt;log4j2.xml&lt;/code&gt;) and would ignore every other file.&lt;/p&gt;

&lt;p&gt;To ensure all resources of our application are copied including non-filtered ones, we must add a second &lt;code&gt;&amp;lt;resource&amp;gt;&lt;/code&gt; tag with filtering disabled and which excludes the filtered files. The list of files to exclude in the second &lt;code&gt;&amp;lt;resource&amp;gt;&lt;/code&gt; tag is the same as the included files in the first resource configuration.&lt;/p&gt;

&lt;p&gt;With the configuration above, only our &lt;code&gt;test.txt&lt;/code&gt; file is filtered and any other file in our resource folder (or its sub-folders) will not be filtered, allowing us to use &lt;code&gt;${project.name}&lt;/code&gt; without worrying that it could be replaced by Maven.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring resources filtering for Log4j2
&lt;/h2&gt;

&lt;p&gt;Applying resource filtering to automatically inject some information now becomes very easy. The first step is to take the code above and enable filtering for log4j2.xml:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;project&amp;gt;&lt;/span&gt;
  ...
  &lt;span class="nt"&gt;&amp;lt;build&amp;gt;&lt;/span&gt;
    ...
    &lt;span class="nt"&gt;&amp;lt;resources&amp;gt;&lt;/span&gt;
      &lt;span class="c"&gt;&amp;lt;!-- Enable filtering for specific resources --&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;resource&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;directory&amp;gt;&lt;/span&gt;src/main/resources&lt;span class="nt"&gt;&amp;lt;/directory&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;filtering&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/filtering&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;includes&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;include&amp;gt;&lt;/span&gt;log4j2.xml&lt;span class="nt"&gt;&amp;lt;/include&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/includes&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/resource&amp;gt;&lt;/span&gt;
      &lt;span class="c"&gt;&amp;lt;!-- Disable filtering for everything else.
           This part is necessary so Maven continues to copy non-filtered resources.
      --&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;resource&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;directory&amp;gt;&lt;/span&gt;src/main/resources&lt;span class="nt"&gt;&amp;lt;/directory&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;filtering&amp;gt;&lt;/span&gt;false&lt;span class="nt"&gt;&amp;lt;/filtering&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;excludes&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;exclude&amp;gt;&lt;/span&gt;log4j2.xml&lt;span class="nt"&gt;&amp;lt;/exclude&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/excludes&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/resource&amp;gt;&lt;/span&gt;
      ...
    &lt;span class="nt"&gt;&amp;lt;/resources&amp;gt;&lt;/span&gt;
    ...
  &lt;span class="nt"&gt;&amp;lt;/build&amp;gt;&lt;/span&gt;
  ...
&lt;span class="nt"&gt;&amp;lt;/project&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With our Log4J2 configuration file now filtered, we can easily use the properties defined in our &lt;code&gt;pom.xml&lt;/code&gt; to enrich our logs. Let's configure a RollingFile appender that output JSON logs (more info in my post &lt;a href="https://dev.to/gauthierplm/how-to-output-log4j2-logs-as-json-5an3"&gt;How to output Log4J2 logs as JSON?&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;...
&lt;span class="nt"&gt;&amp;lt;RollingFile&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"json-file"&lt;/span&gt; &lt;span class="na"&gt;fileName=&lt;/span&gt;&lt;span class="s"&gt;"${sys:mule.home}${sys:file.separator}logs${sys:file.separator}${project.artifactId}.log.json"&lt;/span&gt;
                 &lt;span class="na"&gt;filePattern=&lt;/span&gt;&lt;span class="s"&gt;"${sys:mule.home}${sys:file.separator}logs${sys:file.separator}${project.artifactId}-%i.log.json"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;JSONLayout&lt;/span&gt; &lt;span class="na"&gt;compact=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;eventEol=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;properties=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;stacktraceAsString=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;includeTimeMillis=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!--  Project properties --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;KeyValuePair&lt;/span&gt; &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="s"&gt;"appName"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"${project.name}"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;KeyValuePair&lt;/span&gt; &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="s"&gt;"version"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"${project.version}"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/JSONLayout&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/RollingFile&amp;gt;&lt;/span&gt;
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our logs will now come with two additional properties: the application name and its version. You can now leverage these additional information, or any other properties extracted from your &lt;code&gt;pom.xml&lt;/code&gt;, to enrich your logs and improve their filtering in a tool like &lt;a href="https://www.datadoghq.com/" rel="noopener noreferrer"&gt;Datadog&lt;/a&gt; or &lt;a href="https://www.splunk.com/" rel="noopener noreferrer"&gt;Splunk&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;Resource filtering is a very useful feature of Maven's &lt;a href="https://maven.apache.org/plugins/maven-resources-plugin/index.html" rel="noopener noreferrer"&gt;&lt;code&gt;maven-resource-plugin&lt;/code&gt;&lt;/a&gt; plugin, allowing you to inject properties from your &lt;code&gt;pom.xml&lt;/code&gt; into your resources. With a simple configuration of that plugin, references to properties are injected into your resources when your application is built.&lt;/p&gt;

</description>
      <category>mulesoft</category>
      <category>maven</category>
      <category>log4j2</category>
      <category>java</category>
    </item>
    <item>
      <title>Fish: Start ssh-agent on session opening on MacOS</title>
      <dc:creator>Gauthier POGAM--LE MONTAGNER</dc:creator>
      <pubDate>Tue, 23 Aug 2022 12:34:00 +0000</pubDate>
      <link>https://dev.to/gauthierplm/fish-start-ssh-agent-on-session-opening-on-macos-2884</link>
      <guid>https://dev.to/gauthierplm/fish-start-ssh-agent-on-session-opening-on-macos-2884</guid>
      <description>&lt;p&gt;A while ago, I switched to Fish after getting tired of setting up my ZSH after a new system reset (yes, I should backup my config files...). One of the thing I missed however was a proper setup of my ssh agent on session opening. Let's see how to set it up in a few minutes.&lt;/p&gt;

&lt;h1&gt;
  
  
  What is SSH Agent?
&lt;/h1&gt;

&lt;p&gt;When relying a lot on SSH to log on other machines or to push code using Git (or any other version control system), it starts to be pretty inconvenient to enter your password each time. That's where &lt;a href="https://www.ssh.com/academy/ssh/agent" rel="noopener noreferrer"&gt;SSH Agent&lt;/a&gt; will help: it is a deamon (process running in the background) that will save your SSH private key and its password in its memory and will enter them for you when opening an SSH session.&lt;/p&gt;

&lt;p&gt;While being a very common tool in the Unix world, the version on MacOS has a few additions that allow it to use the system' keychain to store and encrypt your password, increasing the security of your SSH Agent setup.&lt;/p&gt;

&lt;h1&gt;
  
  
  What is Fish?
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://fishshell.com/" rel="noopener noreferrer"&gt;Fish&lt;/a&gt; is a wonderful Shell with many things ready out-of-the box, making it the most convenient shell I used without having to customise it. If you want to learn more about Fish, there are good articles here on dev.to, and the &lt;a href="https://fishshell.com/docs/current/index.html" rel="noopener noreferrer"&gt;Fish &lt;/a&gt;doc does a good job at presenting it.&lt;/p&gt;

&lt;h1&gt;
  
  
  Fisher, the plugin manager
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://github.com/jorgebucaran/fisher" rel="noopener noreferrer"&gt;Fisher&lt;/a&gt; is a simple and convenient plugin manager for Fish. With a single command, you can install new plugins, update them, or remove them, without ever having to change any file. Convenient! Therefore, I recommend &lt;a href="https://github.com/jorgebucaran/fisher#installation" rel="noopener noreferrer"&gt;to install it&lt;/a&gt; to simplify your plugin management.&lt;/p&gt;

&lt;p&gt;Like most shells, Fish has quite a few plugin managers. Feel free to pick the one that suits you the best if you already have one. If you use a different plugin manager, you should be able to easily change the command to install the plugin with it.&lt;/p&gt;

&lt;h1&gt;
  
  
  Enabling SSH Agent at launch
&lt;/h1&gt;

&lt;p&gt;While searching for a way to automatically enable SSH Agent on MacOS, I found that the usual commands you run on most Unix systems are valid but they are not taking advantage of &lt;a href="https://support.apple.com/guide/keychain-access/what-is-keychain-access-kyca1083/mac" rel="noopener noreferrer"&gt;MacOS' keychain&lt;/a&gt;. Using the keychain allow decryption of your private' key password when you login while protecting it when you aren't logged thanks to the encryption of the keychain.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/nifoc/ssh-agent-macos.fish" rel="noopener noreferrer"&gt;plugin&lt;/a&gt; was written and published by nifoc and ensure only a single session of the process is started in your user. I reviewed the code and did not find anything fishy in it, so I decided to use it.&lt;/p&gt;

&lt;p&gt;To install it, simply run &lt;code&gt;fisher install nifoc/ssh-agent-macos.fish&lt;/code&gt;. This will download the plugin and add its files in the right directories of your fish configuration folder (&lt;code&gt;.config/fish&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;To add your SSH key to the agent and save its password in the keychain, run &lt;code&gt;ssh-add --apple-use-keychain&lt;/code&gt;. You will be prompted for your password and once entered correctly, it will be saved in your Mac' keychain.&lt;/p&gt;

&lt;p&gt;Each time your shell will be opened, the key will be loaded by the agent and made available without having to enter your SSH password every time you use open an SSH session.&lt;/p&gt;

&lt;h1&gt;
  
  
  Security consideration
&lt;/h1&gt;

&lt;p&gt;As using SSH Agent allows anyone with access to your session to use your SSH key as they want, remember to encrypt the disk of your Mac, add a password to your session (and diable auto-connect), and make sure to lock your session when going away from your computer. We never know what might happen!&lt;/p&gt;

</description>
      <category>fish</category>
      <category>shell</category>
      <category>macos</category>
    </item>
    <item>
      <title>How to easily rebuild an app after editing a resource?</title>
      <dc:creator>Gauthier POGAM--LE MONTAGNER</dc:creator>
      <pubDate>Fri, 08 Jul 2022 10:48:17 +0000</pubDate>
      <link>https://dev.to/gauthierplm/how-to-easily-rebuild-an-app-after-editing-a-resource-3c83</link>
      <guid>https://dev.to/gauthierplm/how-to-easily-rebuild-an-app-after-editing-a-resource-3c83</guid>
      <description>&lt;p&gt;When editing resource files in &lt;a href="https://www.mulesoft.com/platform/studio" rel="noopener noreferrer"&gt;Anypoint Studio&lt;/a&gt; such as the log configuration, property files, or DataWeave files, you probably noticed that the application is not automatically rebuilt and deployed by the Studio. This is because the Studio only tracks files in &lt;code&gt;src/main/mule&lt;/code&gt; or files that are used as &lt;a href="https://docs.mulesoft.com/mule-runtime/4.4/transform-move-transformations-separate-file-studio-task" rel="noopener noreferrer"&gt;resources of a Transform Message component&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is very inconvenient as starting a new runtime can take a very long time, even with good hardware. Fortunately, there is an easy way to manually trigger the build and redeployment of one or multiple applications that are already running.&lt;/p&gt;

&lt;p&gt;Let me show you how to redeploy your app easily. First, open the Project menu and select "Clean...":&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffwtthx5eaownvfdzu6lp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffwtthx5eaownvfdzu6lp.png" alt=" " width="242" height="268"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This opens a window where I can either clean all projects, triggering a rebuild of all projects, or select one or more projects that I want to rebuild:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6ekh67jvlfrqbw9at8uc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6ekh67jvlfrqbw9at8uc.png" alt=" " width="541" height="369"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this screenshot, only my Experience API will be rebuilt. If the application was already deployed, the runtime will now automatically redeploy it without restarting the whole runtime.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tip&lt;/strong&gt;: if your application does not automatically redeploy after editing a Mule Configuration File, make sure "Build Automatically" is checked in the Project menu (see the first screenshot above).&lt;/p&gt;

</description>
      <category>mulesoft</category>
    </item>
    <item>
      <title>How to output Log4J2 logs as JSON?</title>
      <dc:creator>Gauthier POGAM--LE MONTAGNER</dc:creator>
      <pubDate>Fri, 18 Feb 2022 13:00:30 +0000</pubDate>
      <link>https://dev.to/gauthierplm/how-to-output-log4j2-logs-as-json-5an3</link>
      <guid>https://dev.to/gauthierplm/how-to-output-log4j2-logs-as-json-5an3</guid>
      <description>&lt;p&gt;&lt;strong&gt;Edit&lt;/strong&gt;: the instructions in this blog post can be applied to any Log4J configuration, not only Mule applications. I mostly talk about Mule apps as I felt this topic is poorly documented while the need for it is very common in Mule dev teams.&lt;/p&gt;

&lt;p&gt;Mulesoft platform is very convenient to manage the whole life-cycle of Mule applications. However, reviewing your application' logs can be unpractical as Anypoint Platform' log viewer is limited and not available for all subscription levels. To address this issue or to better integrate with your organisation log management tool, you might want to configure your applications to output logs in the JSON format before collecting them and sending them to your log management platform.&lt;/p&gt;

&lt;p&gt;This blog post will guide you through the changes you need to make to Log4J2 to output logs as JSON and where to configure this in your Mule applications. I tried to explain the various components we are manipulating as I was a bit lost myself when I started to configure my logs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why choosing JSON as your output format?
&lt;/h2&gt;

&lt;p&gt;If you ever opened a JSON log file, you probably noticed that logs in JSON format are unreadable. Writing logs as text is much easier to read for humans.&lt;/p&gt;

&lt;p&gt;However, in a production environment, you don't want to SSH directly on the server to read the logs. Additionally, your company might be using log centralisation tools such as Datadog or Splunk that are shared between teams and centralise logs in a single tool.&lt;/p&gt;

&lt;p&gt;For these tools, parsing of text logs can be tricky. You have to write complicated parsing rules using regular expressions to extract data from the text logs that might be hard to maintain. Additionally, every time you want to add a new information to your log, you'd have to edit the pattern in your Log4J2 configuration and updating your parsing rules to extract the new information.&lt;/p&gt;

&lt;p&gt;With JSON Layout, every log is structured in a JSON object that contains not only the log message and its status, but also the context information related to it. With each value in a different field, no parsing is needed to extract the various information about or log as they are all available in dedicated fields.&lt;/p&gt;

&lt;p&gt;This is an example of a JSON formatted log:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"timeMillis"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1641027600000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"thread"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"WrapperListener_stop_runner"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"level"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"INFO"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"loggerName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"org.mule.runtime.core.internal.logging.LogUtil"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;**********************************************************************&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;* Application shut down normally on: 01/01/22    *&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;* 12:00                                                              *&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;* Up for: 0 days, 1 hours, 1 mins, 1.000 sec                       *&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;**********************************************************************"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"endOfBatch"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"loggerFqcn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"org.apache.logging.slf4j.Log4jLogger"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"contextMap"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"threadId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"threadPriority"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"appName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my-test-api"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0-SNAPSHOT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"apiType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my-type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"service"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my-test-api"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Recap about Log4J2
&lt;/h2&gt;

&lt;p&gt;Log4J2 is a logging framework, a Java library that you can extensively configure to output logs in the format and following the layout that suits your needs.&lt;/p&gt;

&lt;p&gt;To do so, you need to &lt;a href="https://logging.apache.org/log4j/2.x/manual/configuration.html" rel="noopener noreferrer"&gt;configure Log4J2&lt;/a&gt; using the format you prefer, such as properties file, XML, YAML, ... For this example, we will use the XML format but all these instructions can be easily adapted to other configuration formats.&lt;/p&gt;

&lt;p&gt;A few definitions before we starts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://logging.apache.org/log4j/2.x/manual/appenders.html" rel="noopener noreferrer"&gt;&lt;strong&gt;Appenders&lt;/strong&gt;&lt;/a&gt; are the various channels which you can use to output your logs. For example, you can use the &lt;a href="https://logging.apache.org/log4j/2.x/manual/appenders.html#RollingFileAppender" rel="noopener noreferrer"&gt;RollingFileAppender&lt;/a&gt; to output logs in a file and rename the file when conditions (named &lt;a href="https://logging.apache.org/log4j/2.x/manual/appenders.html#TriggeringPolicies" rel="noopener noreferrer"&gt;Trigger Policies&lt;/a&gt;) are met, or the &lt;a href="https://logging.apache.org/log4j/2.x/manual/appenders.html#HttpAppender" rel="noopener noreferrer"&gt;HttpAppender&lt;/a&gt; which sends logs via HTTP to a target URL.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://logging.apache.org/log4j/2.x/manual/layouts.html" rel="noopener noreferrer"&gt;&lt;strong&gt;Layouts&lt;/strong&gt;&lt;/a&gt; are defining how a log entry will be output. Log4J2 are offering different layouts, such as the &lt;a href="https://logging.apache.org/log4j/2.x/manual/layouts.html#PatternLayout" rel="noopener noreferrer"&gt;Pattern Layout&lt;/a&gt;, which define a text-formatted log, or the &lt;a href="https://logging.apache.org/log4j/2.x/manual/layouts.html#JSONLayout" rel="noopener noreferrer"&gt;JSON Layout&lt;/a&gt; that we will use.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://logging.apache.org/log4j/2.x/manual/index.html" rel="noopener noreferrer"&gt;Log4J2 documentation&lt;/a&gt; is very complete and I strongly recommend you to read it to see everything possible with Log4J2.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring Log4J2
&lt;/h2&gt;

&lt;p&gt;As mentioned earlier, Log4J2 configuration can be written in many languages. In Mule applications, the configuration uses the XML format and is located in &lt;code&gt;src/main/resources/log4j2.xml&lt;/code&gt;, the default path for Maven projects.&lt;/p&gt;

&lt;p&gt;This files contains the various appenders configured for your application (including their layout) as well as the loggers configuration, which define the level of the various log categories of your application. This is an example of Mule' &lt;a href="https://docs.mulesoft.com/mule-runtime/4.4/logging-in-mule#configuring-custom-logging-settings" rel="noopener noreferrer"&gt;default Log4J2 configuration&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Configuration&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Appenders&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Console&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Console"&lt;/span&gt; &lt;span class="na"&gt;target=&lt;/span&gt;&lt;span class="s"&gt;"SYSTEM_OUT"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;PatternLayout&lt;/span&gt; &lt;span class="na"&gt;pattern=&lt;/span&gt;&lt;span class="s"&gt;"%-5p %d [%t] %c: %m%n"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/Console&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Appenders&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;Loggers&amp;gt;&lt;/span&gt;

        &lt;span class="c"&gt;&amp;lt;!-- CXF is used heavily by Mule for web services --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;AsyncLogger&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"org.apache.cxf"&lt;/span&gt; &lt;span class="na"&gt;level=&lt;/span&gt;&lt;span class="s"&gt;"WARN"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

        &lt;span class="c"&gt;&amp;lt;!-- Apache Commons tend to make a lot of noise which can clutter the log--&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;AsyncLogger&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"org.apache"&lt;/span&gt; &lt;span class="na"&gt;level=&lt;/span&gt;&lt;span class="s"&gt;"WARN"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

        &lt;span class="c"&gt;&amp;lt;!-- Reduce startup noise --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;AsyncLogger&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"org.springframework.beans.factory"&lt;/span&gt; &lt;span class="na"&gt;level=&lt;/span&gt;&lt;span class="s"&gt;"WARN"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

        &lt;span class="c"&gt;&amp;lt;!-- Mule classes --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;AsyncLogger&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"org.mule"&lt;/span&gt; &lt;span class="na"&gt;level=&lt;/span&gt;&lt;span class="s"&gt;"INFO"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;AsyncLogger&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"com.mulesoft"&lt;/span&gt; &lt;span class="na"&gt;level=&lt;/span&gt;&lt;span class="s"&gt;"INFO"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;AsyncRoot&lt;/span&gt; &lt;span class="na"&gt;level=&lt;/span&gt;&lt;span class="s"&gt;"INFO"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;AppenderRef&lt;/span&gt; &lt;span class="na"&gt;ref=&lt;/span&gt;&lt;span class="s"&gt;"Console"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/AsyncRoot&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Loggers&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/Configuration&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The JSON Layout
&lt;/h3&gt;

&lt;p&gt;In the example above, the &lt;code&gt;Console&lt;/code&gt; appender is using the Pattern Layout, which outputs logs as text. We will replace this layout by a &lt;code&gt;JSONLayout&lt;/code&gt; to output our logs as JSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Appenders&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Console&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Console"&lt;/span&gt; &lt;span class="na"&gt;target=&lt;/span&gt;&lt;span class="s"&gt;"SYSTEM_OUT"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;JSONLayout&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Console&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Appenders&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you run your application and check the console, you will notice that your logs are now formatted in JSON. This JSON is probably taking a lot of lines, so we will configure our appender to output a more compact format, and add a few options to improve our log:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Appenders&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Console&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Console"&lt;/span&gt; &lt;span class="na"&gt;target=&lt;/span&gt;&lt;span class="s"&gt;"SYSTEM_OUT"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;JSONLayout&lt;/span&gt; &lt;span class="na"&gt;compact=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;eventEol=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;properties=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;stacktraceAsString=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;includeTimeMillis=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Console&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Appenders&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's detail these new options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;compact&lt;/code&gt; will write the JSON log without writing any space or new line between keys. This will make it harder to read but will take much less space in the log file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;eventEol&lt;/code&gt; will append an end-of-line character (&lt;code&gt;\n&lt;/code&gt;) after each record, writing one log per line in your log file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;properties&lt;/code&gt; will add the thread context map in the generated JSON. The thread context map includes the correlation ID, the processor path and every variables added to the logging context using the &lt;a href="https://docs.mulesoft.com/tracing-module/1.0/" rel="noopener noreferrer"&gt;Tracing Module&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;stacktraceAsString&lt;/code&gt; will write stacktraces as a single string instead of nested objects. This will simplify integration in log management tools and will make it easier to read as each line will end with the new line caracter (&lt;code&gt;\n&lt;/code&gt;), allowing a JSON reader to properly format the stacktrace.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;includeTimeMillis&lt;/code&gt; will output the log' time as a timestamp with millisecond precision instead of an instant object, allowing log management tools to properly set the time of a log entry.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These settings will ensure that our log takes the minimum amount of space when written while adding all the necessary informations in an easy to parse format.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding properties
&lt;/h3&gt;

&lt;p&gt;When using the JSON layout, you can specify additional properties that will be added to your log payload. These properties might be used to add informations about the log that are otherwise unknown to Log4J2 such as the name or version of your application, the type of API it implements (&lt;code&gt;experience&lt;/code&gt;, &lt;code&gt;process&lt;/code&gt; or &lt;code&gt;system&lt;/code&gt;), or any information you might find useful.&lt;/p&gt;

&lt;p&gt;Properties can be added as children of the &lt;code&gt;JSONLayout&lt;/code&gt; tag by using the &lt;code&gt;KeyValuePair&lt;/code&gt; tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;JSONLayout&lt;/span&gt; &lt;span class="na"&gt;compact=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;eventEol=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;properties=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;stacktraceAsString=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;includeTimeMillis=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;KeyValuePair&lt;/span&gt; &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="s"&gt;"appName"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"my-app"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;KeyValuePair&lt;/span&gt; &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="s"&gt;"version"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"1.0.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;KeyValuePair&lt;/span&gt; &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="s"&gt;"appType"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"process"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/JSONLayout&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Associated with &lt;a href="https://maven.apache.org/plugins/maven-resources-plugin/examples/filter.html" rel="noopener noreferrer"&gt;Maven' resource filtering&lt;/a&gt;, it is even possible to extract these informations from the project' pom.xml. I will write another article on how to use Maven' filtering soon, but here is an example of what we use internally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;JSONLayout&lt;/span&gt; &lt;span class="na"&gt;compact=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;eventEol=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;properties=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;stacktraceAsString=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;includeTimeMillis=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!--  Project properties --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;KeyValuePair&lt;/span&gt; &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="s"&gt;"appName"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"${project.name}"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;KeyValuePair&lt;/span&gt; &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="s"&gt;"version"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"${project.version}"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;KeyValuePair&lt;/span&gt; &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="s"&gt;"appType"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"${app.type}"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/JSONLayout&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Writing logs to a JSON file
&lt;/h2&gt;

&lt;p&gt;Now that our logs are formatted in JSON and contains every information we need, we will configure Log4J2 so it outputs logs in a &lt;a href="https://logging.apache.org/log4j/2.x/manual/appenders.html#RollingFileAppender" rel="noopener noreferrer"&gt;RollingFileAppender&lt;/a&gt;. To do this, we will replace our &lt;code&gt;Console&lt;/code&gt; appender by the &lt;code&gt;RollingFileAppender&lt;/code&gt; and configure it to write logs in a file named &lt;code&gt;my-app.log.json&lt;/code&gt;, under the logs folder of our runtime. Files will be rolled once the log file' size reach 10MB, and the last 10 files will be kept on the disk:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Appenders&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;RollingFile&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"json-file"&lt;/span&gt; &lt;span class="na"&gt;fileName=&lt;/span&gt;&lt;span class="s"&gt;"${sys:mule.home}${sys:file.separator}logs${sys:file.separator}my-app.log.json"&lt;/span&gt;
             &lt;span class="na"&gt;filePattern=&lt;/span&gt;&lt;span class="s"&gt;"${sys:mule.home}${sys:file.separator}logs${sys:file.separator}my-app-%i.log.json"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;JSONLayout&lt;/span&gt; &lt;span class="na"&gt;compact=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;eventEol=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;properties=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;stacktraceAsString=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;includeTimeMillis=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="c"&gt;&amp;lt;!--  Project properties --&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;KeyValuePair&lt;/span&gt; &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="s"&gt;"appName"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"${project.name}"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;KeyValuePair&lt;/span&gt; &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="s"&gt;"version"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"${project.version}"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;KeyValuePair&lt;/span&gt; &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="s"&gt;"appType"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"${app.type}"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/JSONLayout&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;SizeBasedTriggeringPolicy&lt;/span&gt; &lt;span class="na"&gt;size=&lt;/span&gt;&lt;span class="s"&gt;"10 MB"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;DefaultRolloverStrategy&lt;/span&gt; &lt;span class="na"&gt;max=&lt;/span&gt;&lt;span class="s"&gt;"10"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/RollingFile&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Appenders&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this appender, logs will be written in &lt;code&gt;$MULE_HOME/logs/my-app.log.json&lt;/code&gt;. When a new log is produced by your application, it will be added to the tail of the file. When your log file' size exceed 10 MB, it will be renamed as &lt;code&gt;$MULE_HOME/logs/my-app-1.log.json&lt;/code&gt; and a new file &lt;code&gt;$MULE_HOME/logs/my-app.log.json&lt;/code&gt; will be created. When the new file is full, &lt;code&gt;$MULE_HOME/logs/my-app-1.log.json&lt;/code&gt; is renamed to &lt;code&gt;$MULE_HOME/logs/my-app-2.log.json&lt;/code&gt;, &lt;code&gt;$MULE_HOME/logs/my-app.log.json&lt;/code&gt; to &lt;code&gt;$MULE_HOME/logs/my-app-1.log.json&lt;/code&gt; and a new &lt;code&gt;$MULE_HOME/logs/my-app.log.json&lt;/code&gt; is created.&lt;/p&gt;

&lt;p&gt;The files will continue to roll until 10 of them exists, at which point the oldest file will be deleted. This is very convenient to keep the most recent files on the disk but avoiding filling your disk while keeping the most recent logs available for debug.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to easily read JSON files?
&lt;/h3&gt;

&lt;p&gt;If you open one of these JSON log files, you will notice that it is very hard to read. You could copy-paste their content into a JSON beautifier, but this is far from convenient and will make you loose a lot of time.&lt;/p&gt;

&lt;p&gt;Instead, I recommend the &lt;a href="https://stedolan.github.io/jq/" rel="noopener noreferrer"&gt;&lt;code&gt;jq&lt;/code&gt;&lt;/a&gt; command. This command will allow you to format you JSON as well as filter them and choose the fields you want to see. It can be installed on any machine and makes it very easy to prettify your JSON file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat my-app.log.json | jq
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Now that you logs are written in JSON log files, they become much easier to integrate into your log management platform. Data can easily be parsed by platforms that usually support JSON logs natively, mapping is much easier as each information is in its own field, and you can add new properties to your JSON logs with only a short line of XML.&lt;/p&gt;

&lt;p&gt;And to show you the final result of our setup, this is a Log4J2 file that we use and which rely on JSON logging and Mule resource filtering to produce informative and easy to parse logs picked by Datadog agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;Configuration&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Appenders&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- Human readable logs for easy debugging via SSH --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;RollingFile&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"file"&lt;/span&gt; &lt;span class="na"&gt;fileName=&lt;/span&gt;&lt;span class="s"&gt;"${sys:mule.home}${sys:file.separator}logs${sys:file.separator}${project.artifactId}.log"&lt;/span&gt;
                 &lt;span class="na"&gt;filePattern=&lt;/span&gt;&lt;span class="s"&gt;"${sys:mule.home}${sys:file.separator}logs${sys:file.separator}${project.artifactId}-%i.log"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;PatternLayout&lt;/span&gt; &lt;span class="na"&gt;pattern=&lt;/span&gt;&lt;span class="s"&gt;"%-5p %d [%t] [%MDC] %c: %m%n"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;SizeBasedTriggeringPolicy&lt;/span&gt; &lt;span class="na"&gt;size=&lt;/span&gt;&lt;span class="s"&gt;"10 MB"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;DefaultRolloverStrategy&lt;/span&gt; &lt;span class="na"&gt;max=&lt;/span&gt;&lt;span class="s"&gt;"10"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/RollingFile&amp;gt;&lt;/span&gt;

        &lt;span class="c"&gt;&amp;lt;!-- JSON formatted logs consummed by our Datadog agent --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;RollingFile&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"json-file"&lt;/span&gt; &lt;span class="na"&gt;fileName=&lt;/span&gt;&lt;span class="s"&gt;"${sys:mule.home}${sys:file.separator}logs${sys:file.separator}${project.artifactId}.log.json"&lt;/span&gt;
                 &lt;span class="na"&gt;filePattern=&lt;/span&gt;&lt;span class="s"&gt;"${sys:mule.home}${sys:file.separator}logs${sys:file.separator}${project.artifactId}-%i.log.json"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;JSONLayout&lt;/span&gt; &lt;span class="na"&gt;compact=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;eventEol=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;properties=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;stacktraceAsString=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;includeTimeMillis=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="c"&gt;&amp;lt;!--  Project properties--&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;KeyValuePair&lt;/span&gt; &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="s"&gt;"appName"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"${project.name}"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;KeyValuePair&lt;/span&gt; &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="s"&gt;"version"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"${project.version}"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;KeyValuePair&lt;/span&gt; &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="s"&gt;"appType"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"${app.type}"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class="c"&gt;&amp;lt;!--  Datadog log ingestion properties --&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;KeyValuePair&lt;/span&gt; &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="s"&gt;"service"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"${project.artifactId}"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/JSONLayout&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;SizeBasedTriggeringPolicy&lt;/span&gt; &lt;span class="na"&gt;size=&lt;/span&gt;&lt;span class="s"&gt;"10 MB"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;DefaultRolloverStrategy&lt;/span&gt; &lt;span class="na"&gt;max=&lt;/span&gt;&lt;span class="s"&gt;"10"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/RollingFile&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Appenders&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Loggers&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- Http Logger shows wire traffic on DEBUG. --&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!--AsyncLogger name="org.mule.service.http.impl.service.HttpMessageLogger" level="DEBUG" /&amp;gt;--&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;AsyncLogger&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"org.mule.service.http"&lt;/span&gt; &lt;span class="na"&gt;level=&lt;/span&gt;&lt;span class="s"&gt;"WARN"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;AsyncLogger&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"org.mule.extension.http"&lt;/span&gt; &lt;span class="na"&gt;level=&lt;/span&gt;&lt;span class="s"&gt;"WARN"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

        &lt;span class="c"&gt;&amp;lt;!-- Mule logger --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;AsyncLogger&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"org.mule.runtime.core.internal.processor.LoggerMessageProcessor"&lt;/span&gt; &lt;span class="na"&gt;level=&lt;/span&gt;&lt;span class="s"&gt;"INFO"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;AsyncRoot&lt;/span&gt; &lt;span class="na"&gt;level=&lt;/span&gt;&lt;span class="s"&gt;"INFO"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;AppenderRef&lt;/span&gt; &lt;span class="na"&gt;ref=&lt;/span&gt;&lt;span class="s"&gt;"file"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;AppenderRef&lt;/span&gt; &lt;span class="na"&gt;ref=&lt;/span&gt;&lt;span class="s"&gt;"json-file"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/AsyncRoot&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Loggers&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Configuration&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>mulesoft</category>
      <category>java</category>
      <category>logging</category>
      <category>log4j</category>
    </item>
    <item>
      <title>Mulesoft Clusters not synchronizing: tips to solve common issue</title>
      <dc:creator>Gauthier POGAM--LE MONTAGNER</dc:creator>
      <pubDate>Thu, 06 Jan 2022 17:25:58 +0000</pubDate>
      <link>https://dev.to/gauthierplm/mulesoft-clusters-not-synchronizing-tips-to-solve-common-issue-5hij</link>
      <guid>https://dev.to/gauthierplm/mulesoft-clusters-not-synchronizing-tips-to-solve-common-issue-5hij</guid>
      <description>&lt;p&gt;To ensure reliability, we use &lt;strong&gt;Mule Clusters&lt;/strong&gt; to synchronize our runtimes and ensure high availability between our applications.&lt;/p&gt;

&lt;p&gt;Contrary to &lt;strong&gt;Server Groups&lt;/strong&gt; which only deploy applications on all servers, Clusters also allow the runtimes to synchronize with each other. When clustered, their in-memory caches are synchronized and the schedulers are run only on the primary node.&lt;/p&gt;

&lt;p&gt;After upgrading to Mule 4.4, we noticed that our schedulers were run on every runtimes in our cluster, resulting in the same operation being processed multiple times when the scheduler would run. The cluster had the same behaviour as Server Groups: they were not synchronized and schedulers and caches were managed individually on each node.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the issue: clusters logs
&lt;/h2&gt;

&lt;p&gt;By default, Mule runtimes do not output logs related to clusters. If there is an issue, the runtime will fail silently to create the cluster and you will have no way to know there is a problem as nothing is reported in the Runtime Manager either.&lt;/p&gt;

&lt;p&gt;To help you find the root cause, you can enable cluster logs from your runtime Log4J2 configuration (located in &lt;code&gt;$MULE_HOME/conf/log4j2.xml&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;AsyncLogger&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"com.mulesoft.mule.runtime.module.cluster"&lt;/span&gt; &lt;span class="na"&gt;level=&lt;/span&gt;&lt;span class="s"&gt;"DEBUG"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;AsyncLogger&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"com.hazelcast.internal.cluster"&lt;/span&gt; &lt;span class="na"&gt;level=&lt;/span&gt;&lt;span class="s"&gt;"DEBUG"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By adding these two lines in the &lt;code&gt;Loggers&lt;/code&gt; section of your configuration, the cluster logs will be written in &lt;code&gt;$MULE_HOME/logs/mule_ee.log&lt;/code&gt;. The setup of the cluster is one of the first operation done at runtime startup; you can find the corresponding log entries just after the runtime boots up.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://help.mulesoft.com/s/article/How-to-Verify-if-the-Mule-Cluster-is-Working-Correctly" rel="noopener noreferrer"&gt;Link to official documentation.&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;$MULE_HOME/.mule/mule-cluster.properties&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;If the cluster was not properly setup for some reason, the cluster configuration file might not be created. In this case, you will have an error saying that &lt;code&gt;$MULE_HOME/.mule/mule-cluster.properties&lt;/code&gt; could not be found.&lt;/p&gt;

&lt;p&gt;This problem is a bit tricky because the file cannot be regenerated without editing the cluster, or created by hand if you manage your cluster using the runtime manager.&lt;/p&gt;

&lt;p&gt;First, verify if the file &lt;code&gt;$MULE_HOME/.mule/mule-cluster.properties&lt;/code&gt; does exists and if not, make sure the runtime has the rights to write in &lt;code&gt;$MULE_HOME&lt;/code&gt; and &lt;code&gt;$MULE_HOME/.mule/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If the file is missing, we must trigger an update of the cluster configuration, which will rewrite &lt;code&gt;mule-cluster.properties&lt;/code&gt; on every nodes of the cluster. To do so, you must change the number of nodes in the cluster. You can do it in two ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install the runtime on a new server and add it to the cluster. This is time consuming if you don't have any server ready and no automation to install the runtime.&lt;/li&gt;
&lt;li&gt;Remove a server from the cluster and add it back. This is the preferred solution but it will not avoid downtime.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's see how to proceed with the second solution:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;First, you need to make sure there is at least 2 nodes up in your cluster with your application deployed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the runtime manager, go in the &lt;strong&gt;Servers&lt;/strong&gt; page and click on your cluster's name to open its settings.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the server list, click on the server you would like to remove (we will add it back in a second).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;At the top of the opened page, click on &lt;strong&gt;Remove Server From Cluster&lt;/strong&gt;. The server you removed and the other nodes in the cluster will now restart and the cluster status will be in the status Created if there is only one node in it.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You will now have to wait for a few minutes so every applications restart properly in the cluster. You will notice that no application is deployed on the node your just removed from the cluster.&lt;/p&gt;

&lt;p&gt;In the meantime, you can SSH into your cluster' nodes and check whether &lt;code&gt;$MULE_HOME/.mule/mule-cluster.properties&lt;/code&gt; has been created properly. If so, you can open it and will find the property &lt;code&gt;mule.cluster.nodes&lt;/code&gt; listing all nodes in your cluster.&lt;/p&gt;

&lt;p&gt;When every application has been restarted in the cluster, you can &lt;a href="https://docs.mulesoft.com/runtime-manager/cluster-add-srv" rel="noopener noreferrer"&gt;add the node back to the cluster&lt;/a&gt;. This will trigger a new restart of the applications, but your nodes should now be able to communicate with each other.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ensuring the nodes can communicate
&lt;/h2&gt;

&lt;p&gt;By default, all nodes should be on the same network and will use ports 5701, 5702 and 5703 to communicate with each others. If you have an error stating that the clusters could not communicate with each other, the two runtimes might not have the rights to call each other.&lt;/p&gt;

&lt;p&gt;Make sure that all runtimes in your cluster fulfil &lt;a href="https://docs.mulesoft.com/mule-runtime/4.4/mule-high-availability-ha-clusters#prerequisites" rel="noopener noreferrer"&gt;the pre-requites&lt;/a&gt; and reach to your network team if something is not working properly.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;This small guide tries to save your some time but does not cover every issues you might encounter with your cluster. If you still have issues with your cluster, contact Mulesoft support: they know their product much more than I do!&lt;/p&gt;

</description>
      <category>mulesoft</category>
      <category>systems</category>
    </item>
    <item>
      <title>DataWeave: accept lambda as parameter of a function</title>
      <dc:creator>Gauthier POGAM--LE MONTAGNER</dc:creator>
      <pubDate>Mon, 03 Jan 2022 14:07:33 +0000</pubDate>
      <link>https://dev.to/gauthierplm/dataweave-accept-lambda-as-parameter-of-a-function-5aa8</link>
      <guid>https://dev.to/gauthierplm/dataweave-accept-lambda-as-parameter-of-a-function-5aa8</guid>
      <description>&lt;p&gt;When writing DataWeave code, it is common to use functions that take a lambda as parameter, such as &lt;code&gt;map&lt;/code&gt; or &lt;code&gt;flatten&lt;/code&gt;. Using lambda in DataWeave is well documented and easy to understand for developers that already worked with functional programming in other languages.&lt;/p&gt;

&lt;p&gt;However, creating a DataWeave function that accepts a lambda as parameter, while relatively easy, is not well documented in Mulesoft' documentation.&lt;/p&gt;

&lt;p&gt;As creating functions taking lambda as parameters can be very useful, I will explain how to pass a lambda as parameter of a function. Common use cases are to accept a callback or apply a transformation or a predicate passed as a parameter.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a lambda?
&lt;/h2&gt;

&lt;p&gt;In functional programming, data are immutable and thus cannot be modified. To &lt;em&gt;change&lt;/em&gt; a value, we do not modify it directly. Instead, the value is processed and a new value defined.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nx"&gt;dw&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;initialValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;21&lt;/span&gt;
&lt;span class="c1"&gt;// Error: a variable cannot be modified after its declaration&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;newValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;
&lt;span class="c1"&gt;// Success: a new variable is created containing the new value.&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;newValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Arrays follow the same principle and their values cannot be modified. Instead, we will use functions that applies some behaviour to each element. This behaviour is defined in a lambda, a function without a name that can be saved in a variable or passed as a parameter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nx"&gt;dw&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;initialValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;newValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;initialValue&lt;/span&gt; &lt;span class="nf"&gt;map &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;newValue&lt;/span&gt; &lt;span class="c1"&gt;// [2, 4, 6]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the example above, &lt;code&gt;(value) -&amp;gt; value * 2&lt;/code&gt; is a lambda that takes the existing value and multiply it by 2. This function is passed as a parameter of map.&lt;/p&gt;

&lt;p&gt;DataWeave allows a lambda to you anonymous parameters, and to be passed without being surrounded by variables. This shorten the code and can make it more clear. The following line does the same thing as its equivalent above:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;var newValue = initialValue map $ * 2&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;For more information, refer to &lt;a href="https://docs.mulesoft.com/dataweave/2.4/dataweave-functions-lambdas" rel="noopener noreferrer"&gt;Mulesoft's documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Taking lambdas as parameters
&lt;/h2&gt;

&lt;p&gt;To write a function that accepts a lambda as parameter, you need two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Define the parameter and type it so it is clear it accepts a lambda.&lt;/li&gt;
&lt;li&gt;Call the lambda and give it the required parameters.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To define and type the parameter, you must specify the parameter name and the signature of the function it accepts:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;helloNewYear(lambda: (param1: String, param2: Number) -&amp;gt; String) = ...&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In this example, we declare a function &lt;code&gt;helloNewYear&lt;/code&gt; that accepts one parameter: a lambda. This lambda should be a function accepting a String and a Number as parameter, and returning a String.&lt;/p&gt;

&lt;p&gt;Once we have our parameter, we need to call it. It is called in the same way as any other function, taking the parameter name as function name:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;helloNewYear(lambda: (param1: String, param2: Number) -&amp;gt; String) = lambda("Hello", 2022)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now, we can call our function and pass it the lambda we want to execute:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;helloNewYear((sentence, year) -&amp;gt; sentence ++ " " ++ year)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This will output "Hello 2022". Your lambda can contain any behaviour you wish to define.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code Example
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nx"&gt;dw&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt;

&lt;span class="c1"&gt;// Processing function that takes a lambda as parameter&lt;/span&gt;
&lt;span class="nx"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;updateEvenCharacters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// The type of the parameter is the expected signature of the lambda to call&lt;/span&gt;
    &lt;span class="nx"&gt;mapper&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="nx"&gt;str&lt;/span&gt; &lt;span class="nx"&gt;splitBy&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;
        &lt;span class="c1"&gt;// The lambda is called as a normal function, with the parameter name being the function name&lt;/span&gt;
        &lt;span class="nf"&gt;map &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="nf"&gt;isEven&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$$&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="nf"&gt;mapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;$$&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;joinBy&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;

&lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;plain&lt;/span&gt;
&lt;span class="o"&gt;---&lt;/span&gt;
&lt;span class="c1"&gt;// Call the processing function and pass a lambda as second parameter &lt;/span&gt;
&lt;span class="nf"&gt;updateEvenCharacters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello World!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// The parameter should be the lambda to call.&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;  &lt;span class="nf"&gt;upper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;__&lt;/p&gt;

</description>
      <category>mulesoft</category>
      <category>dataweave</category>
    </item>
  </channel>
</rss>
