Tuesday, January 7, 2025

AEM Servlet Complete Guide


 

After reading this Article, You should have an Understanding of


  • What is Sling Servlets ?
  • Types of Sling Servlets

  • Java Servlet Life Cycle
  • Lifecycle of an AEM Servlet
  • Key difference between Normal Servlet and AEM Servlet
  • What are Sling Servlets?
    • Restrictions on Sling Servlets
    • Step-by-Step Flow and Architecture of Sling Servlets 
    • Servlet Registration
    • A Sling servlet can be registered in two ways
    • Important Properties in Servlet Annotations
    • Resource Type vs Path-Based Servlets
  • Real Time Example for Create Path Based Servlet
    • Requirement
    • Approach to Implement the Requirement
    • Implement the logic for Dynamic Pages
    • let's Understand the code
  • Real Time Example for Create Resource Type Servlet
    • Requirement

What is a Servlet?

A servlet is a Java class designed to enhance the functionality of servers by handling client requests and generating responses, typically in web-based applications.

Think of it as a bridge between a web server and the backend logic that determines what the user sees or does. While servlets can handle many tasks, they’re primarily used to add dynamic features to web servers.

Java Servlet Life Cycle










Loading and Instantiation

  • The servlet container loads the servlet class when the application starts or when the servlet is accessed for the first time (depending on configuration).
  • The servlet class is loaded into memory.
  • An instance of the servlet is created using the default no-argument constructor.

Initialization (init method)

  • The init() method is called once, after the servlet instance is created.
  • The servlet is initialized with configuration data from the deployment descriptor (web.xml) or annotations.
  • This is where resources like database connections are set up.

Request Handling (service method)

  • For every client request, the container invokes the service() method.
  • The service() method determines the type of request (e.g., GET, POST) and dispatches it to the appropriate method, such as doGet() or doPost().
  • The servlet processes the request and generates a response.

Destruction (destroy method)

  • The servlet container shuts down or the servlet is explicitly removed.
  • The destroy() method is called to release resources.
  • Any cleanup operations, such as closing database connections, occur here.

Lifecycle of an AEM Servlet


AEM servlets are managed differently due to AEM’s reliance on the OSGi framework and Sling models. These servlets are primarily designed to work in the context of AEM components and the JCR (Java Content Repository).


Component Declaration

  • The servlet is declared as an OSGi component using annotations like @Component, @Service, and @SlingServletPaths and @SlingServletResourceTypes.
  • The OSGi container identifies the servlet as a service.
  • The servlet is registered based on its resource type, path, or selector.

Dependency Injection 

  • Before the servlet is initialized, the OSGi container injects dependencies into the servlet.
  • Services such as ResourceResolverFactory or SlingHttpServletRequest are injected into the servlet.
  • This ensures the servlet can interact with AEM’s resource tree and JCR. 

Activation (@Activate method)

  • The servlet becomes active when its required dependencies are satisfied.
  • An optional @Activate method can be used to initialize configurations or resources when the servlet is activated.

Request Handling

  • The Sling framework dispatches HTTP requests to the servlet based on the registered path, resource type, or selector.
  • The servlet processes the request (usually within the doGet() or doPost() methods).
  • The servlet interacts with AEM’s resource tree and JCR to dynamically render content or perform backend logic.
Deactivation (@Deactivate method)
  • The servlet is deactivated when the bundle is stopped or unregistered.
  • Any resources initialized during activation are released.
  • The servlet is effectively removed from the OSGi container. 

Key Differences Between Normal Servlets and AEM Servlets
















What are Sling Servlets?

Sling Servlets are server-side components used in Sling-based applications to handle HTTP requests and generate responses. They are an integral part of Adobe Experience Manager (AEM) development.

These servlets are registered as OSGi services, which means they are modular and can be dynamically managed at runtime. OSGi serves as the backbone for AEM, built on top of Sling and JCR (Java Content Repository).

Sling itself is a REST-based framework that simplifies access to JCR content over the web. Sling Servlets leverage this framework to process dynamic content and implement custom business logic in AEM.















Sling Servlet Configuration and Constraints
Mandatory Properties
  • Either the sling.servlet.paths or the sling.servlet.resourceTypes service reference property must be set. If neither is set, the Servlet service is ignored.
Handling Conflicts
  • If both sling.servlet.paths and sling.servlet.resourceTypes are set, the servlet is registered using both approaches.
Property Precedence
  • If the sling.servlet.paths property is set, all other sling.servlet.* properties are ignored.
Resource Provider Registration
  • If sling.servlet.paths is not set, a Resource Provider is registered for the servlet for every permutation of resource type, selector, extension, and method.









Types of Sling Servlets
In Sling, there are two types of servlets, each servlets is designed for different HTTP methods. When creating a servlet, it's important to select the appropriate type based on the operations you want to perform.
SlingSafeMethodsServlet
  • Use this servlet if your requirements only involve read-only HTTP methods, such as GET, HEAD, and OPTIONS.
  • This class extends the basic HttpServlet class and enhances its functionality, offering greater flexibility and control over which methods to implement.
  • It's ideal when you only need to fetch data without altering anything on the server.
SlingAllMethodsServlet
  • This is an extended version of SlingSafeMethodsServlet that includes support for POST, PUT, and DELETE methods. 
  • Choose this servlet type when you need to handle both read and write operations, allowing you to handle tasks like submitting data, updating records, or deleting resources.
Step-by-Step Flow and Architecture of Sling Servlets
Below is a detailed explanation of how a request flows through Sling in AEM, from a web browser to the servlet, and back again.





















Step 1: Request from the Web Browser or End User
  • The process starts when a web browser or End User sends a request to the server using HTTP or HTTPS.
  • This request could either be to retrieve data (GET request) or to submit data (POST request).
Step 2: Sling Intercepts the Request
  • The Sling framework identifies that the request is directed to AEM and uses its built-in URL mapping mechanisms to handle it.
  • This ensures that the correct servlet or resource processes the request.
Step 3: Resolve the Resource
Sling resolves the resource using two main types of mappings:
 Path-Based Mapping:
  • In this method, the servlet is registered using sling.servlet.paths or the @SlingServletPaths annotation.
  • For example, a URL like /bin/example directly maps to the servlet responsible for processing it.   
 Resource Type Mapping:
  • The servlet is registered using sling.servlet.resourceTypes or the @SlingServletResourceTypes annotation.
  • For instance, a request to /content/example will match the resource type example/components/content, which then resolves to the appropriate servlet.
Step 4: Match the Servlet
The Sling Servlet Resolver determines the appropriate servlet to handle the request by checking
  • The paths property for path-based mapping.
  • The resourceTypes property for resource type-based mapping.
Step 5: Dispatcher’s Role in Caching
  • Before reaching AEM, the request first goes to the Dispatcher, which checks if the requested data is already cached.
  • If cached, the response is sent back to the browser immediately. Otherwise, the Dispatcher forwards the request to the AEM instance for further processing.
Step 6: Servlet Processing
The servlet receives the request and processes it based on the request type and data
  • It might validate or apply business logic to the incoming data.
  • The servlet may save the processed data to a database or retrieve data from the database to send it back to the browser.
Step 7: Data Formats and Response
  • Communication between the browser and server happens in predefined formats such as JSON, XML, or binary.
  • Once the servlet finishes processing, it sends the response back to the browser in the same format, ensuring smooth communication and display
Servlet Registration
@Component 
  • In AEM, the @Component annotation is used to register a Sling Servlet as an OSGi service. OSGi allows different parts of the application to be treated as services.
  • By adding this annotation, you’re essentially telling AEM to treat your servlet as a service that can process specific HTTP requests based on its configuration.
A Sling servlet can be registered in two ways
Using Resource Types
  • we use sling:resourceType property of the node. This allows us to map a servlet to a specific resource type. To use this method, you simply need to hit the path in the browser that corresponds to the defined sling:resourceType.
Using Paths
  • In this case, the servlet is registered directly to a specific path. When you hit this path in the browser, the corresponding servlet gets executed.
Important Properties in Servlet Annotations
Important properties you need to know when configuring servlets with the above methods
  • sling.servlet.paths: This property defines the exact path used to access the servlet.
  • sling.servlet.resourceTypes: It maps a resource to a specific servlet. This helps to define which resource types will trigger the servlet.
  • sling.servlet.methods: Used to specify the methods for which the servlet is responsible, such as GET, POST, DELETE, etc.
  • sling.servlet.selectors: Selectors are special parameters that you can use to pass additional data to the servlet code. This property is only considered if you're using the sling.servlet.resourceTypes method.
  • sling.servlet.extensions: This allows the servlet to handle different file extensions, such as .txt, .json, or .html, making it more flexible in terms of the types of requests it can respond to.
Resource Type vs Path-Based Servlets
When deciding between using a resource type-based servlet or a path-based servlet in AEM, there are a few important differences to consider:













Resource Type-Based Servlets
  • Security: The Sling engine automatically handles permissions for resource type-based servlets. This means only users who have permission to access the resource can trigger the servlet, making it more secure compared to path-based servlets.
  • How it works: With resource types, the system first accesses the resource, then calls the servlet. This makes it a structured way of handling requests.
  • Control: The servlet gets executed based on the resource type, which is easier to manage from a security perspective and aligns better with AEM's access control system.
Path-Based Servlets
  • Limitations: Path-based servlets can only be mapped to specific paths, not resource types. They also don’t handle suffixes in the URL as flexibly as resource type servlets.
  • Risk of errors: If the servlet isn’t active, a POST request could lead to unexpected results. Path-based servlets need more careful attention to avoid errors.
  • Paths need to be exact: When defining paths for path-based servlets, you need to be specific, or the servlet might not function correctly. A mistake in defining the path can break the servlet.
Real Time Example for Create Path Based Servlet
Requirement:
  • The business team has requested for create dynamically new pages in the AEM site structure. For example, when a specific action is triggered (e.g., a form submission or a scheduled task), a new page should be created under a specific section of the website. The page should use a predefined template, have a meaningful name, and include metadata like the page title and page name. Additionally, the solution it should allow input parameter of parent path, page name and page title.
Approach to Implement the Requirement
Step 1: Understand the Requirement
  • The business needs a way to programmatically create pages in the AEM content structure.
  • The pages should Be created under a specific parent path dynamically provided via input.
  • Use a specific template.
  • Have a meaningful page name and page title dynamically provided via input
Step 2: Choose the Right option for Implementation
  • To meet this requirement, we can use an AEM servlet.
  • Servlets allow us to handle incoming HTTP requests (like GET or POST) and perform actions like creating pages dynamically.
Step 3: Plan the Implementation
To create the pages dynamically, we need to:
  • Use the ResourceResolver to interact with the AEM repository.
  • Use the PageManager to create pages dynamically.
  • Handle exceptions and ensure proper resource cleanup.
Implement the logic for DynamicPages
  • Before Creating Servlets Go to http://localhost:4502/system/console/configMgr and Search for “Servlet/Script Resolver” you will find servlet path is added inside the execution path field, if not then first you need to add this.
  • below is the screenshot for refrenece 


  • creating a servlet named CreateDynamicPages.java” which extends “SlingAllSafeMethodServlet”.
Here is the complete code:

import com.day.cq.wcm.api.PageManager;
import com.day.cq.wcm.api.Page;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.servlets.HttpConstants;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.Servlet;
import java.io.IOException;

@Component(service = Servlet.class,
        property = {
                Constants.SERVICE_DESCRIPTION + "=Create Page Servlet",
                "sling.servlet.methods=" + HttpConstants.METHOD_GET,
                "sling.servlet.paths=" + "/bin/createDynamicPages"
        })
public class CreateDynamicPages extends SlingAllMethodsServlet {

        private static final Logger log = LoggerFactory.getLogger(CreateDynamicPages.class);

        @Override
        protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response)
                throws IOException {


                log.info("----------< Executing Create Page Servlet >----------");


                try (ResourceResolver resourceResolver = request.getResourceResolver()) {

                        PageManager pageManager = resourceResolver.adaptTo(PageManager.class);
                        if (pageManager == null) {
                                log.error("PageManager is not available");
                                response.getWriter().write("Error: PageManager is not available");
                                return;
                        }
                        String parentPath = request.getParameter("parentPath");
                        String pageName = request.getParameter("pageName");
                        String templatePath = "/conf/aem-debugcode/Generic/settings/wcm/templates/generic-template";
                        String pageTitle = request.getParameter("pageTitle");

                        if (parentPath == null || pageName == null || pageTitle == null) {
                                response.getWriter().write("Error: Missing required parameters");
                                return;
                        }

                        Page newPage = pageManager.create(parentPath, pageName, templatePath, pageTitle);

                        if (newPage != null) {
                                log.info("Page created successfully: {}", newPage.getPath());
                                response.getWriter().write("Page created successfully: " + newPage.getPath());
                        } else {
                                log.error("Failed to create page");
                                response.getWriter().write("Error: Failed to create page");
                        }

                } catch (Exception e) {
                        log.error("Error while creating page: {}", e.getMessage(), e);
                        response.getWriter().write("Error: " + e.getMessage());
                }
        }
}

OUTPUT:


let's Understand the code


  • The servlet receive incoming requests at a specific URL (e.g., /bin/createDynamicPages?parentPath=/content/aem-debugcode/us/en&pageTitle=LandingPage&pageName=landPage).
  • Extract parameters from the request
    • Use request.getParameter("parentPath"), request.getParameter("pageName")and request.getParameter("pageTitle") to get user inputs.
  • Use the ResourceResolver from the incoming request to gain access to the JCR (Java Content Repository), which stores all content in AEM.
  • Use the PageManager to create a page with the dynamically provided parent path and page name and page title.
  • Build a response message indicating the page creation status, including the path of the created page.
  • Close the ResourceResolver properly to avoid memory leaks.
Real Time Example for Create Resource Type Servlet

Requirement:
  • The business team has requested a solution to dynamically fetch and display the list of child pages for a specific page in the AEM site structure
Approach to Implement the Requirement
  • Accept a pagePath parameter as input to specify the parent page.
  • Default to the path /content/aem-debugcode/us/en if no pagePath parameter is provided.
  • Retrieve all child pages under the specified parent page and return their titles and paths in a structured format.
  • Support response formats in JSON or plain text (txt).
Here is the complete code 
import java.io.IOException;
import java.util.Iterator;

import javax.json.Json;
import javax.json.JsonArrayBuilder;
import javax.json.JsonObjectBuilder;
import javax.servlet.Servlet;
import javax.servlet.ServletException;

import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
import org.apache.sling.servlets.annotations.SlingServletResourceTypes;
import org.osgi.service.component.annotations.Component;

import com.day.cq.wcm.api.Page;
import com.day.cq.wcm.api.PageManager;



@Component(service = Servlet.class)
@SlingServletResourceTypes(resourceTypes = "aem-debugcode/components/page",
        selectors = "list", extensions = {"txt", "json"})
public class AccessComponentsServlet extends SlingSafeMethodsServlet {

    @Override
    protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response)
            throws ServletException, IOException {

        ResourceResolver rr = request.getResourceResolver();
        String pagePath = request.getParameter("pagePath");
        if (pagePath == null) {
            pagePath = "/content/aem-debugcode/us/en";
        }
        PageManager pm = rr.adaptTo(PageManager.class);
        Page page = pm.getPage(pagePath);
        Iterator<Page> childPages = page.listChildren();
        JsonArrayBuilder jsonObj = Json.createArrayBuilder();
        while (childPages.hasNext()) {
            JsonObjectBuilder jsonBuilder = Json.createObjectBuilder();
            Page selectedPage = childPages.next();
            jsonBuilder.add("title", selectedPage.getTitle());
            jsonBuilder.add("path", selectedPage.getPath());
            jsonObj.add(jsonBuilder);
        }
        response.getWriter().write(jsonObj.build().toString());
    }
}

  • Hit this URL - http://localhost:4502/content/aem-debugcode/us/en/jcr:content.list.txt
OUTPUT:
[
  {
    "title": "My Account",
    "path": "/content/aem-debugcode/us/en/my-account"
  },
  {
    "title": "Catalog Page",
    "path": "/content/aem-debugcode/us/en/products"
  },
  {
    "title": "Reset Password",
    "path": "/content/aem-debugcode/us/en/reset-password"
  },
  {
    "title": "Search Results",
    "path": "/content/aem-debugcode/us/en/search"
  },
  {
    "title": "Test Page",
    "path": "/content/aem-debugcode/us/en/test-page"
  },
  {
    "title": "New Page",
    "path": "/content/aem-debugcode/us/en/new-page"
  },
  {
    "title": "New Page1",
    "path": "/content/aem-debugcode/us/en/new-page1"
  },
  {
    "title": "New Page1",
    "path": "/content/aem-debugcode/us/en/new-page10"
  },
  {
    "title": "LandingPage",
    "path": "/content/aem-debugcode/us/en/landPage"
  }
]

Logging in AEM

 

After reading this Article, You should have an Understanding of

  • What is Logging?
  • Why Use Logging in AEM?
  • When to Use Logging?
  • How to Implement Logging in AEM
    • Implementing Logging in AEM Using SLF4J Logger
    • Setting up Custom Loggers for Specific Components
      • Option 1: Configure via Sling Configuration Manager
      • Option 2: Use AEM’s Logging Console (global configuration for all log files)
  • Customize log files using logging writer
  • AEM in-Build Log Files in Detail
  • Log Level Hierarchy (from most to least detailed)

What is Logging?


Logging in AEM refers to the practice of recording events and messages during the execution of your application. These logs help developers monitor and debug the application’s behavior, identify errors, and understand the flow of events.

Why Use Logging in AEM?

Debugging: Helps identify and troubleshoot issues by providing realtime insights into what is happening in the system.

Monitoring: Logs enable continuous monitoring of the system to ensure it functions as expected.

Auditing: Helps in tracking actions performed by users, components, or processes for compliance and troubleshooting.

When to Use Logging?

  • During development, for debugging purposes.
  • In production, for monitoring and identifying performance bottlenecks or errors.
  • For tracking user actions or events (e.g., securityrelated events).
How to Implement Logging in AEM

There are some ways to implement logging

  • Using SLF4J Logger (Standard Java Logging)
  • Setting up Custom Loggers for Specific Components:
    • Configure via Sling Configuration Manager
    • Using AEM’s Logging Console

Implementing Logging in AEM Using SLF4J Logger

This is the most common and simplest way to implement logging in AEM.

Steps to Implement:

Import the SLF4J Logger.

To start logging in your AEM application, you need to import the SLF4J Logger library. This logger is part of the SLF4J (Simple Logging Facade for Java) framework and is commonly used across Java applications, including AEM.  


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


Create a logger instance using LoggerFactory.

  • Once you have imported the required classes, you can create a logger instance for your class. This instance will be used to write log messages.
  • To do this, use the LoggerFactory.getLogger() method, passing the current class as the parameter. The logger will automatically associate itself with the class name for easier identification in the logs.

private static final Logger logger = LoggerFactory.getLogger(sample.class);


Use different log levels (e.g., info(), debug(), error(), etc.) to log messages.

Write Log Messages with Different Log Levels:

SLF4J supports multiple log levels messages. You can use the following methods to write logs at different levels:

Info: Used to log general, informational messages about the application’s flow.


  
logger.info("This is an info message.");


Debug: Logs detailed messages useful for debugging. These are typically used during development.


  
logger.debug("This is a debug message.");


Error: Logs error messages when an exception or critical failure occurs.


  
 logger.error("An error occurred: ", exception);


 Warn: Logs warning messages for potential issues that might require attention.


   
logger.warn("This is a warning message.");
 


Trace: Captures fine-grained log messages, typically used for tracking very detailed execution steps


  
 logger.trace("This is a trace message.");


Example:

 
    package com.debug.code.core.models.impl;

        import com.debug.code.core.models.CustomButton;
        import com.fasterxml.jackson.annotation.JsonProperty;
        import com.fasterxml.jackson.annotation.JsonRootName;
        import org.apache.sling.api.SlingHttpServletRequest;
        import org.apache.sling.models.annotations.DefaultInjectionStrategy;
        import org.apache.sling.models.annotations.Exporter;
        import org.apache.sling.models.annotations.ExporterOption;
        import org.apache.sling.models.annotations.Model;
        import org.apache.sling.models.annotations.injectorspecific.ValueMapValue;
        import org.slf4j.Logger;
        import org.slf4j.LoggerFactory;

        @Model(adaptables = SlingHttpServletRequest.class,
                adapters = CustomButton.class,
                defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL,
                resourceType = CustomButtonImpl.RESOURCE_TYPE)
        @Exporter(name = "jackson", extensions = "json", selector = "debugcode",
            options = {
                    @ExporterOption(name="SerializationFeature.WRAP_ROOT_VALUE", value = "true"),
                    @ExporterOption(name="MapperFeature.SORT_PROPERTIES_ALPHABETICALLY", value = "true"),
            })

        @JsonRootName("buttonComponentDetails")
        public class CustomButtonImpl implements CustomButton{

            static final String RESOURCE_TYPE = "aem-debugcode/components/customButton";

            private static final Logger logger = LoggerFactory.getLogger(CustomButtonImpl.class);


            @ValueMapValue
            String buttonText;

            @ValueMapValue
            String urlLink;

            @ValueMapValue
            String targetNewWindow;

            @ValueMapValue
            String anchorName;

            @ValueMapValue
            String assetLink;


            @JsonProperty(value = "button")
            @Override
            public String getButtonText() {
                logger.info("Fetching buttonText property value: {}", buttonText);
                return buttonText;
            }

            @Override
            public String getUrlLink() {
                logger.debug("Fetching urlLink property value: {}", urlLink);
                return urlLink;
            }

            @Override
            public String getTargetNewWindow() {
                logger.debug("Fetching targetNewWindow property value: {}", targetNewWindow);
                return targetNewWindow;
            }

            @Override
            public String getAnchorName() {
                logger.debug("Fetching anchorName property value: {}", anchorName);
                return anchorName;
            }

            @Override
            public String getAssetLink() {
                if (assetLink == null) {
                    logger.warn("assetLink property is null.");
                } else {
                    logger.info("Fetching assetLink property value: {}", assetLink);
                }
                return assetLink;
            }
        }



Setting up Custom Loggers for Specific Components

By default, AEM has different log levels set for various loggers. However, you can control which log levels are printed in your logs using AEM's Sling Logging Console.

You can set log levels (e.g., INFO, DEBUG, ERROR) at the global level or for specific classes or packages.


Option 1: Configure via Sling Configuration Manager

Steps to Configure Log Levels

Navigate to the Sling Configuration Manage
    
    Open your browser and go to: http://localhost:4502/system/console/configMgr.

Locate Apache Sling Logging Logger Configuration:

    In the Configuration Manager, search for "Apache Sling Logging Logger Configuration


















Add or Modify a Logger:
    
    Click on "Create" or "Add a new configuration".

    

















Enter the following details:

Logger Name: Specify the package or class you want to log (e.g., com.debug.code.core.models.impl).

Log Level: Choose the desired level (DEBUG, INFO, ERROR, etc.).
    
Log File: Provide a log file name (e.g., /logs/custom-log.log).

Message Pattern:The java.util.MessageFormat pattern to use for formatting log messages with the root logger. This is a java.util.MessageFormat pattern supporting up to six arguments: 
    
        {0} The timestamp of type java.util.Date, 
        {1} the log marker,
        {2} the name of the current thread, 
        {3} the name of the logger, 
        {4} the log level and
        {5} the actual log message. 
    
If the log call includes a Throwable, the stacktrace is just appended to the message regardless of the pattern.
    
The Pattern can be like this: {0,date,dd.MM.yyyy HH:mm:ss.SSS} *{4}* {2} {3} {5}
    
Logger: Here we define the package name of the application,for which we want to print the logs.You can add multiple packages also.
    
Additivity: If set to false then logs from these loggers would not be sent to any appender attached higher in the hierarchy.

Save the configuration.

















Here is the Output:




















Option 2: Use AEM’s Logging Console (global configuration for all log files)

The AEM Logging Console is a powerful tool to manage logging configurations. It allows developers to control what gets logged, where logs are saved, and the level of detail (log levels) for specific parts of the application

Steps to Configure Logging via the AEM Logging Console

Access the Console

    Open your browser and navigate to the following URL:               http://localhost:4502/system/console/slinglog

Why Use the Console?

    To define new loggers for specific components or packages.
    
    To redirect logs to custom files for better traceability.
    
    To adjust log levels (e.g., DEBUG, INFO, ERROR) for existing loggers.
  
Adding or Modifying a Logger


















Save Changes

   After adding or modifying the logger, click Save to confirm the changes

Log Level Behavior

   Logs will only appear in the specified file.

Customize log files using logging writer

Logging Writer configuration in AEM allows you to customize the behavior of log files

Steps to Customize log files using logging writer

Navigate to the Sling Configuration Manage
    
    Open your browser and go to: http://localhost:4502/system/console/configMgr.

Locate Apache Sling Logging Logger Configuration:

    In the Configuration Manager, search for "Apache Sling Logging Writer Configuration"

   

















Enter the following details:

Log File : Mention Your Log File Name.

Number of Log Files: This will generate how many file need to be generated one the limit is reached it will stop genearting file.

Log File Threshold: By default log file will rotate at 12AM every day 

You can Customize this behavior, This option supports Size and Rotation(date time)

Rotation Options : There are Six Options available
            
   '.'yyyy-MM : When You Specify this option Log File will generate every month of 1st date

   '.'yyyy-ww: When You Specify this option Log File will generate every week of 1st day

   '.'yyyy-MM-dd : When You Specify this option Log File will generate every day at 12AM

   '.'yyyy-MM-dd-a : When You Specify this option Log File will generate Two time in a day at 12AM and 12PM

   '.'yyyy-MM-dd-HH: When You Specify this option Log File will generate at every hour.
    
   '.'yyyy-MM-dd-HH-mm : When You Specify this option Log File will generate at every minute
        
Size : when the file size is exceed then new file will generate. 
  •             KB
  •             MB
  •             GB
 Example : 5KB       

Save the configuration.

AEM in-Build Log Files in Detail

AEM automatically generates several log files to help monitor and troubleshoot the system. Each log file has a specific purpose, and understanding them is key to effectively managing and maintaining your AEM instance
 
Request.log
    
This log captures all incoming requests along with the responses sent from the AEM instance. It’s particularly useful for tracking and evaluating the performance of your AEM setup.

Access.log
    
This log is quite similar to the request.log, but it provides more detailed access information:

Who is accessing the system


What resource is being accessed?


When was the resource accessed


Each entry in access.log is shorter because it combines request and response data in a single line.

What you’ll find in each Access.log line:

Access IP – The IP address of the machine making the request.

            

Access User – The user who sent the request.

            

 Access Time – The time when the request was made.

            

Request Method –  The HTTP method used (GET, POST, PUT, etc.).

            

Access Resource – The resource being requested.

            

Protocol – The protocol (HTTP/1.1 or HTTPS)..

            

Response Status Code – A number indicating the result of the request (e.g., 404, 200).

            

Content Length – The size of the response.

            

Referrer URL – The page that referred the user to the resource.

            

User Agent – The browser and operating system used.


Stdout.log
    
This log tracks the startup process of your AEM instance. It includes details such as sling.home and other important system information during startup

Stderr.log 

Here you’ll find error messages generated during startup or runtime, including things like heap size or other issues. By default, this log is set to a "WARN" level, meaning it only records warnings and above.

Audit.log

Used by Jackrabbit (the content repository in AEM) to log any changes made to the repository. Normally, the log level is set to INFO, so you won’t see many entries unless you change the log level to DEBUG. When set to DEBUG, every change to the repository (such as adding, modifying, or deleting components) gets logged.

History.log 

This log keeps track of user actions like editing, viewing, or deleting content. It’s especially useful for auditing purposes and is primarily relevant on author instances. Each log entry includes:

TimeStamp


Action


User


Content path


Content type(cq:page, dam:asset)


Upgrade.log
    
This log records any upgrade-related activities performed on the system. It’s generated during operations like package updates and is typically set to an INFO log level.

Error.log 

Captures all error messages, including critical issues and lower-level errors that need attention. You can expect to find errors, warnings, and general issue logs in this file.


Log Level Hierarchy (from most to least detailed)
    
TRACE : The most detailed level, usually used for development and debugging.

DEBUG : Used for troubleshooting and understanding the system's internal processes.

INFO : Standard information, such as system status or operational logs.

WARN : Indicates potential problems that may need attention.

ERROR : Critical errors that require immediate attention.