4 Replies Latest reply on Jan 8, 2016 12:43 AM by khantariquealam

    web access logs to syslog (in wildfly 8.2)

    matt.drees

      The basic question is: "How can I configure wildfly 8.2 to send http access log lines to a syslog listener, instead of to a file?"

       

      Background:

      I'm docker-izing an app, and wildfly-ifying it at the same time. I'd like to use the syslog approach for logging, at least for my first attempt. The logging subsystem has a syslog appender, so this works fine for 'normal' logs.

       

      Problem:

      Wildfly/Undertow's http access logs, however, don't seem to use the logging subsystem. If I'm reading it right, the configuration only allows for creating a DefaultAccessLogReceiver. What I'd actually like is to configure a JBossLoggingAccessLogReceiver, which presumably *would* use the logging subsystem.

       

       

      Failed workaround:

      Since wildfly allows attaching extra HttpHandlers, I thought I'd just attach an AccessLogHandler this way. But it doesn't have the appropriate constructor, and the resulting stacktrace looks like this:

       

      17:57:50,090 ERROR [org.jboss.msc.service.fail] (MSC service thread 1-13) MSC000001: Failed to start service jboss.undertow.server.default-server.default-host: org.jboss.msc.service.StartException in service jboss.undertow.server.default-server.default-host: Failed to start service
        at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1904) [jboss-msc-1.2.2.Final.jar:1.2.2.Final]
         ...
      
        at java.lang.Thread.run(Thread.java:745) [rt.jar:1.7.0_65]
      Caused by: java.lang.RuntimeException: JBAS017351: Failed to configure handler class io.undertow.server.handlers.accesslog.AccessLogHandler
        at org.wildfly.extension.undertow.deployment.ConfiguredHandlerWrapper.wrap(ConfiguredHandlerWrapper.java:78)
        at org.wildfly.extension.undertow.filters.CustomFilterDefinition.createHttpHandler(CustomFilterDefinition.java:100)
        at org.wildfly.extension.undertow.filters.FilterService.createHttpHandler(FilterService.java:57)
        at org.wildfly.extension.undertow.filters.FilterRef.createHttpHandler(FilterRef.java:50)
        at org.wildfly.extension.undertow.LocationService.configureHandlerChain(LocationService.java:100)
        at org.wildfly.extension.undertow.Host.configureRootHandler(Host.java:105)
        at org.wildfly.extension.undertow.Host.start(Host.java:83)
        at org.jboss.msc.service.ServiceControllerImpl$StartTask.startService(ServiceControllerImpl.java:1948) [jboss-msc-1.2.2.Final.jar:1.2.2.Final]
        at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1881) [jboss-msc-1.2.2.Final.jar:1.2.2.Final]
        ... 3 more
      Caused by: java.lang.NoSuchMethodException: io.undertow.server.handlers.accesslog.AccessLogHandler.<init>(io.undertow.server.HttpHandler)
        at java.lang.Class.getConstructor0(Class.java:2849) [rt.jar:1.7.0_65]
        at java.lang.Class.getConstructor(Class.java:1718) [rt.jar:1.7.0_65]
        at org.wildfly.extension.undertow.deployment.ConfiguredHandlerWrapper.wrap(ConfiguredHandlerWrapper.java:55)
        ... 11 more
      

       

      So, if I'm reading it right, I'm out of luck. Am I missing something?

       

       

      Also, it seems like this could be fixed easily enough, perhaps by adding a 'target=logging-subsystem' attribute to <access-log>. There are probably other ways too. I might be up for working on a pull request, if someone would be willing to give me some direction.

        • 1. Re: web access logs to syslog (in wildfly 8.2)
          ctomc

          that is an oversight please create jira issue for adding support for that.

           

          As workaround until that, you could implement your own ServletExtension http://undertow.io/documentation/servlet/servlet-extensions.html

          which would wrap root http handler with AccessLogHandler that uses JBossLoggingAccessLogReceiver

          • 2. Re: web access logs to syslog (in wildfly 8.2)
            matt.drees

            Thanks Tomaz. I created [WFLY-4518] enable undertow access logs to use logging subsystem - JBoss Issue Tracker.

             

             

            How would you envision this looking? If it's simple, I might be able to take a go at implementing it.

            Something like this?

             

            /subsystem=undertow/server=default-server/host=default-host/setting=access-log:add( \
                implementation=jboss-logging \
            )
            

             

            (or, alternatively, 'implementation=default')

            • 3. Re: web access logs to syslog (in wildfly 8.2)
              khantariquealam

              Hello Tomaz,

              We are migrating from JBOSS 5 to Wildfly 8.2. In Jboss5, we have written our custom valve implemenation using lucene for searching index(parameter).

              See below

              <Valve className="be.belgacom.tv.common.log4j.BtaAccessLogValve"

                              prefix="localhost_access_log." suffix=".log"

                              pattern='%h %l %u %t %{logID}r %{deviceIdentifier}r %{deviceAddress}r "%r" %s %b %D' directory="${jboss.server.log.dir}"

                              resolveHosts="false" />

              BtaAccessLogValve is our custom valve which was working in Jboss5.

              Now same implementation we want for Wildfly. We can not use servlet extension as we need to provide wildfly admin to configure prefix, pattern and directory.

               

              Please let us know If you have some other approach as we are stuck completely on it.

               

              Regards,

              Tarique

              • 4. Re: web access logs to syslog (in wildfly 8.2)
                khantariquealam

                Sorry for late reply,

                 

                We are able to achieve this filter element and writing our custom exchange attribute builder which would be added Exchange builder list.

                I am adding example code which might help for other wildfly developer.

                 

                E.g.

                Step 1. CustomExchangeAttributeParser(final ClassLoader classLoader, List<ExchangeAttributeWrapper> wrappers)  {

                        this.wrappers = wrappers;

                        ServiceLoader<ExchangeAttributeBuilder> loader = ServiceLoader.load(ExchangeAttributeBuilder.class, classLoader);

                        final List<ExchangeAttributeBuilder> builders = new ArrayList<>();

                        for (ExchangeAttributeBuilder instance : loader) {

                            builders.add(instance);

                        }

                        try {

                  builders.add(BtaLoggerIdExchangeAttribute.Builder.class.newInstance());

                  builders.add(BtaDeviceIdentifierExchangeAttribute.Builder.class.newInstance());

                  builders.add(BtaDeviceAddressExchangeAttribute.Builder.class.newInstance());

                  } catch (InstantiationException e) {

                  // TODO Auto-generated catch block

                  e.printStackTrace();

                  } catch (IllegalAccessException e) {

                  // TODO Auto-generated catch block

                  e.printStackTrace();

                  }

                       // io.undertow.attribute.RelativePathAttribute$Builder@6660bfd4

                        //sort with highest priority first

                        Collections.sort(builders, new Comparator<ExchangeAttributeBuilder>() {

                            @Override

                            public int compare(ExchangeAttributeBuilder o1, ExchangeAttributeBuilder o2) {

                                return Integer.compare(o2.priority(), o1.priority());

                            }

                        });

                        this.builders = Collections.unmodifiableList(builders);

                    }

                Step 2. a. Write handler class and add below code

                @Override

                    public void handleRequest(final HttpServerExchange exchange) throws Exception {

                       

                        if(this.logReceiver == null){

                          this.logReceiver=new BtaAccessLogReceiver(this.worker,new File(this.directory),this.file);

                      }

                        if(this.tokens == null){

                         this.tokens=BtaExchangeAttributes.parser(AccessLogHandler.class.getClassLoader(), new SubstituteEmptyWrapper("-")).parse(this.pattern);

                        }

                    

                        if(this.requestAttributeMap == null){

                        this.requestAttributeMap=BtaExchangeAttributeParser.getRequestAttributeMap();

                        }

                             

                       

                        exchange.addExchangeCompleteListener(new ExchangeCompletionListener() {

                        /**

                        * @param exchange

                        * @param nextListener

                        */

                            @Override

                            public void exchangeEvent(final HttpServerExchange exchange, final NextListener nextListener) {

                                    

                            HashMap<String,String> headerElements=new HashMap<String,String>();

                            for(String key:requestAttributeMap.keySet()){

                            headerElements.put(key, requestAttributeMap.get(key).readAttribute(exchange));

                            }

                            logReceiver.logMessage(tokens.readAttribute(exchange),headerElements);

                                

                                 nextListener.proceed();

                            }

                        });

                 

                 

                        next.handleRequest(exchange);

                    }

                b. On this class, we need accesslog class loader

                final Xnio xnio = Xnio.getInstance("nio", AccessLogReceiver.class.getClassLoader());

                and on constructor

                this.worker=xnio.createWorker(OptionMap.builder().getMap());

                 

                Step 3.

                Now on standalone.xml, inside undertow section, define this as a filter

                <!—accesslog_filter defined in <filters> tag -->

                <filter name="accesslog_filter" class-name="test.customlog.CustomAccessLogHandler" module="be.belgacom.btacommon">

                                    <param name="pattern" value="%h %l %u [%t] %{logID}r %{deviceIdentifier}r %{deviceAddress}r &quot;%r&quot; %s %b %D"/>

                                    <param name="directory" value="${jboss.server.log.dir}"/>

                                    <param name="file" value="access_log."/>

                                </filter>

                <!—filter ref accesslog_filter defined in <host> tag-->

                <filter-ref name="accesslog_filter"/>

                 

                Hope this would help other.

                 

                Enjoy & Happy Coding !