How to add a custom Log Appender? | Community
Skip to main content
Level 4
February 11, 2024
Solved

How to add a custom Log Appender?

  • February 11, 2024
  • 3 replies
  • 849 views

I am trying to wire an Application Insights instance into my AEMaaCS installation.  The idea is that I want to be able to view my logs from application insights, rather than the native AEMaaCS mechanisms.

 

I have installed App Insights and configured the telemetry client.  This code works and I can see the message written to app insights:

 

TelemetryClient client = new TelemetryClient();

client.trackTrace("This is a test...");
 
However, the rest of my application is using the sl4j logger, via code like this:
 
private final Logger _log = LoggerFactory.getLogger(Foo.class);

// ...

_log.info("Hello world");
How can I hook the telemetry client from App Insights into the sl4j logging framework?  I don't see where I can add any appenders via configuration.  Has anyone tried to do this before?
This post is no longer active and is closed to new replies. Need help? Start a new post to ask your question.
Best answer by dylanmccurry

For anyone who stumbles upon this in the future, here's how I have done it:

 

First, you need an Appender created.

 

import java.util.Dictionary; import java.util.Hashtable; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Deactivate; import org.osgi.service.component.propertytypes.ServiceRanking; import com.microsoft.applicationinsights.TelemetryClient; import com.microsoft.applicationinsights.TelemetryConfiguration; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.Appender; import ch.qos.logback.core.AppenderBase; @Component(immediate = true) @ServiceRanking(Integer.MIN_VALUE) public class AppInsightsAppender extends AppenderBase<ILoggingEvent>{ TelemetryClient client = new TelemetryClient(); private static String INSTRUMENTATION_KEY = "<your instrumentation key here>"; private ServiceRegistration sr; public AppInsightsAppender() { setName("AppInsightsAppender"); } @9944223 protected void append(ILoggingEvent e) { // todo: handle all types of events in a more graceful way client.trackTrace(e.getMessage()); } @580286 private void activate(BundleContext bundleContext){ TelemetryConfiguration.getActive().setInstrumentationKey(INSTRUMENTATION_KEY); TelemetryConfiguration.getActive().setTrackingIsDisabled(false); Dictionary<String,Object> props = new Hashtable<String, Object>(); String[] loggers = { "<your root package name here>" }; props.put("loggers",loggers); sr = bundleContext.registerService(Appender.class.getName(),this,props); } @3038739 private void deactivate(){ if(sr != null){ sr.unregister(); } } }

 
The idea behind this appender is that the `append` method is invoked any time a log message is written.

 

Secondarily, if you want to track http calls, you can set up something like this:

 

import java.io.IOException; import java.util.ArrayList; import java.util.List; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.propertytypes.ServiceRanking; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.microsoft.applicationinsights.TelemetryConfiguration; import com.microsoft.applicationinsights.extensibility.TelemetryInitializer; import com.microsoft.applicationinsights.extensibility.TelemetryModule; import com.microsoft.applicationinsights.web.extensibility.initializers.WebOperationIdTelemetryInitializer; import com.microsoft.applicationinsights.web.extensibility.initializers.WebOperationNameTelemetryInitializer; import com.microsoft.applicationinsights.web.extensibility.initializers.WebSessionTelemetryInitializer; import com.microsoft.applicationinsights.web.extensibility.initializers.WebUserAgentTelemetryInitializer; import com.microsoft.applicationinsights.web.extensibility.initializers.WebUserTelemetryInitializer; import com.microsoft.applicationinsights.web.extensibility.modules.WebRequestTrackingTelemetryModule; import com.microsoft.applicationinsights.web.internal.WebRequestTrackingFilter; @Component(immediate = true, service = { Filter.class }, property = { "sling.filter.scope=request" }) @ServiceRanking(Integer.MIN_VALUE) public class AppInsightsFilter implements Filter { private static final Logger LOG = LoggerFactory.getLogger(AppInsightsFilter.class); private WebRequestTrackingFilter webRequestTrackingFilter; private static String INSTRUMENTATION_KEY = "<your instrumentation key here>"; @9944223 public void destroy() { webRequestTrackingFilter.destroy(); } @9944223 public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException { webRequestTrackingFilter.doFilter(servletRequest, servletResponse, filterChain); } @9944223 public void init(final FilterConfig arg0) throws ServletException { webRequestTrackingFilter = new WebRequestTrackingFilter("<your package name here>"); TelemetryConfiguration.getActive().setInstrumentationKey(INSTRUMENTATION_KEY); TelemetryConfiguration.getActive().setTrackingIsDisabled(false); List<TelemetryInitializer> initializers = new ArrayList<>(); initializers.add(new WebOperationIdTelemetryInitializer()); initializers.add(new WebOperationNameTelemetryInitializer()); initializers.add(new WebSessionTelemetryInitializer()); initializers.add(new WebUserTelemetryInitializer()); initializers.add(new WebUserAgentTelemetryInitializer()); TelemetryConfiguration.getActive().getTelemetryInitializers().addAll(initializers); TelemetryModule module = new WebRequestTrackingTelemetryModule(); module.initialize(TelemetryConfiguration.getActive()); TelemetryConfiguration.getActive().getTelemetryModules().add(module); webRequestTrackingFilter.init(arg0); } }


Both of these classes present within the code appears to be enough.  Update your pom.xml dependencies:

 

<dependency> <groupId>com.microsoft.azure</groupId> <artifactId>applicationinsights-web</artifactId> <version>2.5.0</version> <scope>compile</scope> </dependency>

3 replies

pulkitvashisth
Community Advisor
Community Advisor
February 11, 2024

Hi @dylanmccurry 
Checkout Jatin's answer at https://stackoverflow.com/questions/67730720/azure-function-app-logs-into-app-insights-using-slf4j

He has used the logback dependency for the same solution.

Level 4
February 11, 2024

Yes, in the referenced examples it states to add an appender to your XML config file for log4j.  Does this exist in AEMaaCS?  How do I add the telemetry client as an appender in AEMaaCS?

Jagadeesh_Prakash
Community Advisor
Community Advisor
February 12, 2024

hi @dylanmccurry  I haven't tried with telemetry client but once try understanding below article on how to integrate and monitor logs using splunk. Hope this is useful

https://blog.arborydigital.com/splunk-setup-aem-cloud-service-aemaacs

 

dylanmccurryAuthorAccepted solution
Level 4
February 12, 2024

For anyone who stumbles upon this in the future, here's how I have done it:

 

First, you need an Appender created.

 

import java.util.Dictionary; import java.util.Hashtable; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Deactivate; import org.osgi.service.component.propertytypes.ServiceRanking; import com.microsoft.applicationinsights.TelemetryClient; import com.microsoft.applicationinsights.TelemetryConfiguration; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.Appender; import ch.qos.logback.core.AppenderBase; @Component(immediate = true) @ServiceRanking(Integer.MIN_VALUE) public class AppInsightsAppender extends AppenderBase<ILoggingEvent>{ TelemetryClient client = new TelemetryClient(); private static String INSTRUMENTATION_KEY = "<your instrumentation key here>"; private ServiceRegistration sr; public AppInsightsAppender() { setName("AppInsightsAppender"); } @9944223 protected void append(ILoggingEvent e) { // todo: handle all types of events in a more graceful way client.trackTrace(e.getMessage()); } @580286 private void activate(BundleContext bundleContext){ TelemetryConfiguration.getActive().setInstrumentationKey(INSTRUMENTATION_KEY); TelemetryConfiguration.getActive().setTrackingIsDisabled(false); Dictionary<String,Object> props = new Hashtable<String, Object>(); String[] loggers = { "<your root package name here>" }; props.put("loggers",loggers); sr = bundleContext.registerService(Appender.class.getName(),this,props); } @3038739 private void deactivate(){ if(sr != null){ sr.unregister(); } } }

 
The idea behind this appender is that the `append` method is invoked any time a log message is written.

 

Secondarily, if you want to track http calls, you can set up something like this:

 

import java.io.IOException; import java.util.ArrayList; import java.util.List; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.propertytypes.ServiceRanking; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.microsoft.applicationinsights.TelemetryConfiguration; import com.microsoft.applicationinsights.extensibility.TelemetryInitializer; import com.microsoft.applicationinsights.extensibility.TelemetryModule; import com.microsoft.applicationinsights.web.extensibility.initializers.WebOperationIdTelemetryInitializer; import com.microsoft.applicationinsights.web.extensibility.initializers.WebOperationNameTelemetryInitializer; import com.microsoft.applicationinsights.web.extensibility.initializers.WebSessionTelemetryInitializer; import com.microsoft.applicationinsights.web.extensibility.initializers.WebUserAgentTelemetryInitializer; import com.microsoft.applicationinsights.web.extensibility.initializers.WebUserTelemetryInitializer; import com.microsoft.applicationinsights.web.extensibility.modules.WebRequestTrackingTelemetryModule; import com.microsoft.applicationinsights.web.internal.WebRequestTrackingFilter; @Component(immediate = true, service = { Filter.class }, property = { "sling.filter.scope=request" }) @ServiceRanking(Integer.MIN_VALUE) public class AppInsightsFilter implements Filter { private static final Logger LOG = LoggerFactory.getLogger(AppInsightsFilter.class); private WebRequestTrackingFilter webRequestTrackingFilter; private static String INSTRUMENTATION_KEY = "<your instrumentation key here>"; @9944223 public void destroy() { webRequestTrackingFilter.destroy(); } @9944223 public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException { webRequestTrackingFilter.doFilter(servletRequest, servletResponse, filterChain); } @9944223 public void init(final FilterConfig arg0) throws ServletException { webRequestTrackingFilter = new WebRequestTrackingFilter("<your package name here>"); TelemetryConfiguration.getActive().setInstrumentationKey(INSTRUMENTATION_KEY); TelemetryConfiguration.getActive().setTrackingIsDisabled(false); List<TelemetryInitializer> initializers = new ArrayList<>(); initializers.add(new WebOperationIdTelemetryInitializer()); initializers.add(new WebOperationNameTelemetryInitializer()); initializers.add(new WebSessionTelemetryInitializer()); initializers.add(new WebUserTelemetryInitializer()); initializers.add(new WebUserAgentTelemetryInitializer()); TelemetryConfiguration.getActive().getTelemetryInitializers().addAll(initializers); TelemetryModule module = new WebRequestTrackingTelemetryModule(); module.initialize(TelemetryConfiguration.getActive()); TelemetryConfiguration.getActive().getTelemetryModules().add(module); webRequestTrackingFilter.init(arg0); } }


Both of these classes present within the code appears to be enough.  Update your pom.xml dependencies:

 

<dependency> <groupId>com.microsoft.azure</groupId> <artifactId>applicationinsights-web</artifactId> <version>2.5.0</version> <scope>compile</scope> </dependency>
kautuk_sahni
Community Manager
Community Manager
February 21, 2024

@dylanmccurry Did you find the suggestions from users helpful? Please let us know if more information is required. Otherwise, please mark the answer as correct for posterity. If you have found out solution yourself, please share it with the community.

Kautuk Sahni