I have three separate projects, each with their own embedded logback.xml files. Each of these files includes a common logging config file in the user's home durectory:
<include file="${user_home}/loggingConfig.xml"/>
After the include, I have this specification:
<root level="error">
<appender-ref ref="${appender:-console}" />
</root>
This allows the user to configure their log levels and appenders, and have them applied by the core logging config file.
For example, in ~/loggingConfig.xml I have this line:
<property name="appender" value="file" />
But co-workers who prefer console logging leave that line out.
The problem is I would like to use different appenders for each log file. In otherwords, I would like to conditionally set a different appender based on which project is reading the customized config file.
I realize I could configure each project to read differently named config files, but I would like to eliminate the clutter and allow for shared configuration as well.
The documentation is a bit spare for advanced configuration, but I found that you can use the logback context name as a variable with conditional logging. So for each project I define a custom context name in the projects logback.xml file:
<contextName>project1</contextName>
etc...
Then in my ~/loggingConfig.xml file I can do this:
<property name="appender" value="file" />
<!--if condition='property("CONTEXT_NAME").equalsIgnoreCase("project1")'>
<then>
<property name="appender" value="file" />
</then>
</if-->
<if condition='property("CONTEXT_NAME").equalsIgnoreCase("project2")'>
<then>
<property name="appender" value="console" />
</then>
</if>
<if condition='property("CONTEXT_NAME").equalsIgnoreCase("project3")'>
<then>
<property name="appender" value="file" />
</then>
</if>
This can get a bit clunky, but in reality I am using this solution to configure properties used by a single appender for different projects, while still having a graceful fallback to a default value for projects that don't have their own conditional block.
In case this helps anyone else, this is how I set up conditional logback configuration with a property that can contain multiple appenders:
<root level="${logback.loglevel}">
<if condition='isDefined("logback.appenders")'>
<then>
<if condition='property("logback.appenders").contains("CONSOLE")'>
<then>
<appender-ref ref="CONSOLE"/>
</then>
</if>
<if condition='property("logback.appenders").contains("FILE")'>
<then>
<appender-ref ref="FILE"/>
</then>
</if>
<if condition='property("logback.appenders").contains("GELF")'>
<then>
<appender-ref ref="GELF"/>
</then>
</if>
</then>
<else>
<appender-ref ref="CONSOLE"/>
</else>
</if>
</root>
Related
I have a CSV File that I am reading via VFS. After reading the file, I am using Smooks to convert the CSV data into XML and then sending it to another proxy.
By default configuration, smooks converts the whole message into one xml payload.
Problem:
The default method is okay for small files, but I have a very large file to process and I want that I can read the file line by line and then send the message to the next component.
Proxy Configuration:
<proxy xmlns="http://ws.apache.org/ns/synapse"
name="ParseTestCSV1"
startOnLoad="true"
statistics="disable"
trace="disable"
transports="vfs">
<target>
<inSequence>
<log level="full" separator="*********Parsing Prroxy Started*****"/>
<smooks config-key="gov:/repository/csv/smooks-config.xml">
<input type="text"/>
<output type="xml"/>
</smooks>
<log level="full" separator="********After Smooks*******"/>
<property name="OUT_ONLY" value="true"/>
<property action="remove" name="ClientApiNonBlocking" scope="axis2"/>
<call/>
<log level="full" separator="*******Message Sent*********"/>
</inSequence>
<outSequence/>
<faultSequence/>
</target>
<parameter name="transport.PollInterval">60</parameter>
<parameter name="transport.vfs.FileURI">vfs:file://C:\WSO2EnterpriseIntegrator\file\In</parameter>
<parameter name="transport.vfs.ContentType">text/plain</parameter>
<parameter name="transport.vfs.ActionAfterProcess">MOVE</parameter>
<parameter name="transport.vfs.MoveAfterFailure">vfs:file://C:\WSO2EnterpriseIntegrator\file\Fail</parameter>
<parameter name="transport.vfs.ActionAfterFailure">MOVE</parameter>
<parameter name="transport.vfs.FileNamePattern">convert.*.csv</parameter>
<parameter name="transport.vfs.MoveAfterProcess">vfs:file://C:\WSO2EnterpriseIntegrator\file\Out</parameter>
<description/>
</proxy>
Smooks Configuration File:
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd" xmlns:csv="http://www.milyn.org/xsd/smooks/csv-1.2.xsd">
<resource-config selector="org.xml.sax.driver">
<resource>org.milyn.csv.CSVReader</resource>
<param name="fields">$ignore$,firstname,lastname,age,street,address,statecode,postalcode,amount,code,date</param>
<param name="rootElementName">record</param>
<param name="recordElementName">csvRecord</param>
</resource-config>
</smooks-resource-list>
How can I transform my Smook's configuration file to read one line and then send it forward. Any insight would be appreciated.
I've had a similar case, where I had to split a huge XML into a jms message for each order in the XML. You can achive this by using freemaker templates.
Basically you define your freemarker template and bind it to a router.
Example:
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (c) 2005-2010, WSO2 Inc. (http://wso2.com) All Rights Reserved.
~
~ WSO2 Inc. licenses this file to you under the Apache License,
~ Version 2.0 (the "License"); you may not use this file except
~ in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing,
~ software distributed under the License is distributed on an
~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
~ KIND, either express or implied. See the License for the
~ specific language governing permissions and limitations
~ under the License.
-->
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd"
xmlns:core="http://www.milyn.org/xsd/smooks/smooks-core-1.3.xsd"
xmlns:jb="http://www.milyn.org/xsd/smooks/javabean-1.2.xsd"
xmlns:file="http://www.milyn.org/xsd/smooks/file-routing-1.1.xsd"
xmlns:ftl="http://www.milyn.org/xsd/smooks/freemarker-1.1.xsd"
xmlns:jms="http://www.milyn.org/xsd/smooks/jms-routing-1.2.xsd">
<core:namespaces>
<core:namespace prefix="soapenv" uri="http://schemas.xmlsoap.org/soap/envelope/"/>
</core:namespaces>
<core:filterSettings type="SAX" />
<jb:bean beanId="recordsAsXml" class="java.util.Hashtable" createOnElement="records">
<jb:value data="records/Id" decoder="String" property="Id"></jb:value>
<jb:value data="records/Account_ID__c" decoder="String" property="accountID"></jb:value>
<!-- ...-->
</jb:bean>
<ftl:freemarker applyOnElement="records">
<!--<ftl:template>/repository/resources/smooks/record_as_xml.ftl</ftl:template>-->
<ftl:template><!--<order>
<id>${recordsAsXml.Id}</id>
<accountId>${recordsAsXml.accountID}</accountId>
<!-- ...-->
</order>-->
</ftl:template>
<ftl:use>
<ftl:bindTo id="recordAsXmlOutput"/>
</ftl:use>
</ftl:freemarker>
<jms:router routeOnElement="records" beanId="recordAsXmlOutput" destination="MyJMSQueue">
<jms:message>
</jms:message>
<jms:jndi properties="/repository/resources/smooks/activemq.sr.jndi.properties" />
<jms:highWaterMark mark="-1"/>
</jms:router>
</smooks-resource-list>
The following article might also help.
Message processing with smooks
I was reading Scott Gu's blog on ASP.NET 5.0 features and one of the new feature mentioned in the blog is to use json file as configuration and elimination of Web.config file.
I have few questions around that feature.
Assume I have following log4net configuration which was previously added to Web.Config in previous version of ASP.NET
Config file
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
<log4net debug="true">
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="C:\\TestProj\\TestLog.txt" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="10MB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-5p %d %5rms %-22.22c{1} %-18.18M - %m%n" />
</layout>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="RollingLogFileAppender" />
</root>
</log4net>
How would one add sections in config.json ?
How would one convert above xml and add it to config.json?
Does 3rd Party library ( In my example log4net ) or users of the library have to add some type of custom conversion api to support json based configuration, in order to take advantage of new configuration feature provided in ASP.NET 5.0?
Recently I had the same problem with log4net. I managed to do it working as following:
Create log4net.xml file containing the configuration section for log4net
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
...
</log4net>
You can put the file in the project root folder.
And in the Startup.Startup() method you can configure the log4net providing the xml as a configuration:
public Startup(IApplicationEnvironment appEnv)
{
// ...
XmlConfigurator.Configure(new FileInfo(Path.Combine(appEnv.ApplicationBasePath, "log4net.xml")));
}
I hope this helps.
Current versions of log4net don't support Json projects, so the config needs to be in a separate xml file.
I'm trying to remove redundant logback config files by using janino's conditional processing.
Below is the conditional logic which I had added
<root level="INFO">
<appender-ref ref="ROLLING" />
<!-- use console appender on windows, email appender on linux -->
<if condition='property("os.name").contains("win")'>
<then>
<appender-ref ref="CONSOLE" />
</then>
<else>
<appender-ref ref="EMAIL" />
</else>
</if>
</root>
but this throws the below errors
12:30:34,877 |-ERROR in ch.qos.logback.core.joran.spi.Interpreter#90:55 - no applicable action for [if], current pattern is [[configuration][root][if]]
12:30:34,877 |-ERROR in ch.qos.logback.core.joran.spi.Interpreter#91:10 - no applicable action for [then], current pattern is [[configuration][root][if][then]]
12:30:34,877 |-ERROR in ch.qos.logback.core.joran.spi.Interpreter#92:35 - no applicable action for [appender-ref], current pattern is [[configuration][root][if][then][appender-ref]]
12:30:34,877 |-ERROR in ch.qos.logback.core.joran.spi.Interpreter#94:10 - no applicable action for [else], current pattern is [[configuration][root][if][else]]
12:30:34,877 |-ERROR in ch.qos.logback.core.joran.spi.Interpreter#95:35 - no applicable action for [appender-ref], current pattern is [[configuration][root][if][else][appender-ref]]
The configuration works fine if I remove the conditional logic and use something like
<root level="INFO">
<appender-ref ref="ROLLING" />
<appender-ref ref="CONSOLE" />
<appender-ref ref="EMAIL" />
</root>
How can I configure this correctly in such a way that the CONSOLE appender is used only on Windows and the EMAIL appender everywhere else?
Can you try the latest version? I used the latest version and the above conditional statements work perfectly fine
I have tried below config and found that the log rotation happens as expected and a new log file created for every rotation.
However when there are multiple instances of servers are running pointing to same log file. Once the log reaches the limit, the log gets backuped up, but instead of new file (0KB), new logs gets written to the same old file thus incresing the file size.
Looks like in multiple instances, where the file is locked by both instances for writing, the rollback is not proper.
Any workaround/suggestion? well having a new file for each instance is not really an option.
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="" packages="">
<Appenders>
<RollingRandomAccessFile name="RollingRandomAccessFile"
fileName="../logs/ws_new.log" append="false" filePattern=".../logs/ws_new-%d{MM-dd-yyyy}-%i.log">
<PatternLayout>
<Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="50 KB" />
</Policies>
<DefaultRolloverStrategy max="3"/>
</RollingRandomAccessFile>
</Appenders>
<Loggers>
<root level="error">
<AppenderRef ref="RollingRandomAccessFile" />
</root>
<Logger name="org.exm.test" level="trace" additivity="false">
<AppenderRef ref="RollingRandomAccessFile"/>
</Logger>
</Loggers>
</Configuration>
Log4j is not designed to be used that way. If multiple processes try to write to the same log file the results cannot be guaranteed. You may end up losing log messages.
I strongly recommend you have separate log files for your processes.
I'm using Log4Net with Castle.Windsor, the LoggingFacility, and Log4netIntegration. The project I'm using this in involves NHibernate, which also talks to log4net.
What I'm trying to do is split the logs such that NHibernate ends up in one log (data-log.txt), while all the system logging ends up in a separate log (system-log.txt).
The problem I'm having is that it seems like the Logger injected by windsor will only write to the root logger in my log4net configuration. NHibernate looks for loggers named NHibernate or Nhibernate., so I'm able to divert those logs into the data-log.txt appender, but it also writes to the root logger.
So what I've got right now is logs from Windsor and NHibernate all end up with the root logger, and logs from NHibernate additionally end up at the nhibernate specific loggers.
Here is my log4net config section in my app.config:
<log4net xsi:noNamespaceSchemaLocation="http://csharptest.net/downloads/schema/log4net.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<appender name="Console" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%5level [%thread] (%file:%line) - %message%newline"/>
</layout>
</appender>
<appender name="AspNetTraceAppender" type="log4net.Appender.AspNetTraceAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline"/>
</layout>
</appender>
<appender name="NHibernateLogAppender" type="log4net.Appender.RollingFileAppender">
<file value="data-log.txt" />
<!-- various stuff -->
</appender>
<appender name="SystemLogAppender" type="log4net.Appender.RollingFileAppender">
<file value="system-log.txt" />
<!-- various stuff -->
</appender>
<root>
<level value="ALL" />
<appender-ref ref="AspNetTraceAppender" />
<appender-ref ref="Console" />
</root>
<logger name="SystemLogger">
<level value="ALL" />
<appender-ref ref="SystemLogAppender" />
</logger>
<logger name="NHibernate">
<level value="WARN" />
<appender-ref ref="NHibernateLogAppender" />
</logger>
<logger name="NHibernate.SQL">
<level value="DEBUG" />
<appender-ref ref="NHibernateLogAppender"/>
</logger>
and windsor is getting configured by code like so
container.AddFacility<LoggingFacility>(f => f.UseLog4Net().WithAppConfig());
How do I tell Windsor to aim for the SystemLogger instead of the root?
I know one way to do this is by creating a specific logger for each type that wants to use logging, but that seems like a great way to shoot yourself in the foot when you forget about that later.
Have just the root logger with all appenders. Then use appender whitelist and blacklist filtering on logger name:
<appender name="NHibernateLogAppender" type="log4net.Appender.RollingFileAppender">
<file value="data-log.txt" />
<!-- various stuff -->
<filter type="log4net.Filter.LoggerMatchFilter">
<loggerToMatch value="NHibernate" />
</filter>
</appender>
<appender name="SystemLogAppender" type="log4net.Appender.RollingFileAppender">
<file value="system-log.txt" />
<!-- various stuff -->
<filter type="log4net.Filter.LoggerMatchFilter">
<loggerToMatch value="NHibernate" />
<acceptOnMatch value="false" />
</filter>
</appender>
<root>
<level value="ALL" />
<appender-ref ref="NHibernateLogAppender" />
<appender-ref ref="SystemLogAppender" />
</root>
Another route: I've submitted a patch to the Castle.Windsor team that allows users to specify a log name to use.
If you pull and build Windsor from github, LoggingFacility now has a configuration method ToLog(string LogName) that allows you to control which log will be used.