Monday, July 16, 2012

Different ways of logging in WSO2ESB

All wso2 carbon products have a standard way to define a logs .  All logging mechanisms are handled by a carbon logging-mgt component, which is controlled by a central log4j properties file. According to user   needs, he can edit the properties file to get desired log level info in different package level.

When consider ESB product, users have different requirements to acquire the log information in different layers/level of the mediation flow. There are number of ways you can get certain log info in wso2esb.
  • Log mediators :- Users can keep the log mediator in the sequence, and could get certain info about the messages which are passing through certain ESB artifacts
eg:
<log level='full'>
         <property name ='Request message' value='message arrived to insequence'/>
</log> 
  • Editing log4j.properties file to get proxy service level log info:- In this way, user might need to add separate blocks of configuration for all configured proxies. This may be inappropriate in a real production system,where there are hundreds of proxy services deployed and user might need to add hundreds of lines configuration in the log4j.properties file for each proxy service
eg:
 log4j.category.SERVICE_LOGGER.SimpleStockQuoteProxy=INFO, PROXY_APPENDER
log4j.additivity.PROXY_APPENDER=false
log4j.appender.PROXY_APPENDER=org.apache.log4j.DailyRollingFileAppender
log4j.appender.PROXY_APPENDER.File=${carbon.home}/repository/logs/${instance.log}/wso2-esb-stockquote-proxy${instance.log}.log
log4j.appender.PROXY_APPENDER.Append=true
log4j.appender.PROXY_APPENDER.layout=org.apache.log4j.PatternLayout
log4j.appender.PROXY_APPENDER.layout.ConversionPattern=%d{HH:mm:ss,SSS} [%X{ip}-%X{host}] [%t] %5p %c{1} %m%

  •  There is another code level implementation, which can be used to extract some details in certain level of synapse artifacts.
    • eg: Proxy level/Sequence level...
SynapseObserver is an abstract class,which will get notified, whenever a new artifact deployed/undeployed. Each and every  message arrives to the mediation engine will notify the SynapseObserver.
We can extend this observer, to get all proxy service level log information rather adding hundreds line of configuration in the log4j.properties file.
eg:
Code :
import java.io.IOException;
import org.apache.synapse.config.AbstractSynapseObserver;
import org.apache.synapse.core.axis2.ProxyService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.DailyRollingFileAppender;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;

/**
 * This is a custom synapse observer to programatically engage the appender
 * for proxy services.
 *
 */
public class CustomProxyObserver extends AbstractSynapseObserver {
    private static final Log log = LogFactory.getLog(CustomProxyObserver.class);

    public void proxyServiceAdded(ProxyService proxy) {
        try {
            setLogger(proxy);
        } catch (IOException e) {
            log.error("CustomProxyObserver could not set service level logger for the proxy : " +
                      proxy.getName(), e);
        }
    }

    public void proxyServiceRemoved(ProxyService proxy) {
        try {
            setLogger(proxy);
        } catch (IOException e) {
            log.error("CustomProxyObserver could not set service level logger for the proxy : " +
                      proxy.getName(), e);
        }
    }

    /**
     * Method to set proxy service specific logger
     *
     * @param proxy
     * @throws IOException
     */
    private void setLogger(ProxyService proxy) throws IOException {

        String filename = "logs/" + proxy.getName() + ".log";
        String datePattern = "yyyy-MM-dd";
        String SYSTEM_LOG_PATTERN = "[%d] %5p - %x %m {%c}%n";

        PatternLayout layout = new PatternLayout(SYSTEM_LOG_PATTERN);
        DailyRollingFileAppender appender = null;
        appender = new DailyRollingFileAppender(layout, filename, datePattern);
        appender.setName(proxy.getName());       

        Logger proxyLogger = Logger.getLogger("SERVICE_LOGGER." + proxy.getName());
        proxyLogger.setLevel((Level) Level.DEBUG);
        proxyLogger.setAdditivity(false);
        proxyLogger.addAppender(appender);

    }   
   
}
pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>org.wso2.carbon.customobserver</groupId>
    <artifactId>org.wso2.carbon.customobserver</artifactId>
      <version>1.0</version>
    <packaging>bundle</packaging>
 
    <dependencies>
        <dependency>
            <groupId>org.apache.synapse</groupId>
            <artifactId>synapse-core</artifactId>
              <version>2.1.0-wso2v4</version>
            <exclusions>
                <exclusion>
                    <groupId>org.apache.axis2</groupId>
                    <artifactId>axis2-codegen</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    <dependency>
            <groupId>org.eclipse.equinox</groupId>
            <artifactId>org.apache.log4j</artifactId>
            <version>1.2.13</version>
    </dependency>
    <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1.1</version>
    </dependency>       
    </dependencies>

    <build>
        <plugins>       
            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-bundle-plugin</artifactId>
                <version>1.4.0</version>
                <extensions>true</extensions>
                <configuration>
                    <instructions>
                        <Bundle-SymbolicName>${pom.artifactId}</Bundle-SymbolicName>
                        <Bundle-Name>${pom.artifactId}</Bundle-Name>
                          <Export-Package>
                           org.wso2.carbon.customobserver.*,
                        </Export-Package>
                        <Import-Package>
                           !org.apache.log4j.*,
                            !org.apache.commons.logging.*,
                            *;resolution:=optional
                        </Import-Package>
                        <DynamicImport-Package>*</DynamicImport-Package>
                    </instructions>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>
   
 User needs to keep the bundle in the repository/components/dropins folder and need to edit the synapse.properties file to register the CustomObserver

eg:

 synapse.observers=org.wso2.carbon.customobserver.CustomProxyObserver

You will see the generated log files in the ESB_HOME?logs folder.

There is another way, which also needs some coding effort, to extract some specific debug level  information, which are really useful to debug a certain use cases.I'll write about that with sample code and scenario in my next post.

Wednesday, July 11, 2012

Class Endpoints in Synapse

In Apache synapse, there are predefined endpoints , which can be used as service endpoints to send out the message from the mediation engine. Currently available endpoints are;
  • Address Endpoint
  • Default Endpoint 
  • WSDL endpoint
  • Load balance Endpoint 
  • Failover Endpoint 
  • Dynamic Load balance Endpoint

Anyway, Synapse does not support to extend the endpoint capability to add a custom endpoint according to the user needs as in mediators.(ie: class mediator)
To have such a feature, same like class mediator functionality, class endpoint concept has been implemented. The patch has been provided to the synapse project.

To add a class endpoint in the mediation flow, user should add following configuration;
<endpoint name="CustomEndpoint">
                    <class name="org.apache.synapse.endpoint.CustomEndpoint">
                                 <parameter name="foo">XYZ</parameter>*
                    </class>
</endpoint>
The "CustomEndpoint" class implementation should be the child class of the AbstractEndpoint class. Using this type of class endpoints, user can add his own message sending logic or can load a custom synapse environment for a particular endpoint.

Related post: http://vvratha.blogspot.com/2013/06/class-endpointssample.html