log4j2 runtime reconfiguration not working - empty file created - log4j2

I am trying to manually reconfigure log4j2 at runtime but getting partial success.
Here is the relevant code:
package examples.test;
public class ABCImpl implements XYX{
static Logger logger;
public void initialize(){
LoggerContext ctx = null;
Configuration config = null;
Map mp = null;
ctx = (LoggerContext) LogManager.getContext(false);
config = (Configuration)ctx.getConfiguration();
mp = config.getAppenders();
System.out.println("***<Provider o/p follows> Before logger re-configuration:");
System.out.println("\tAppenders:" + mp.keySet());
//reconfiguration attempt - starts
try{
URI configuration = this.getClass().getResource("/log4j2.xml").toURI();
ctx = Configurator.initialize(this.getClass().getName(), null, configuration);
}catch(Exception e){
System.out.println("\t-------Exception encountered-------");
e.printStackTrace();
}
config = (Configuration) ctx.getConfiguration();
mp = config.getAppenders();
System.out.println("***<Provider o/p follows> After logger re-configuration:");
System.out.println("\tAppenders:" + mp.keySet());
//reconfiguration attempt - ends
logger = LogManager.getLogger(this.getClass().getName());
}
public void myBusinessMethod(){
logger.info("Entry..............");
logger.info("Exit..............");
}
}
This class is actually part of a jar file and am running it inside an application server which guarantees that my initialize method would be called as soon as my class is instantiated.
Here is my log4j2.xml, which I have packed into jar's root:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Don't forget to set system property
-DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
to make all loggers asynchronous. -->
<Configuration status="info">
<Appenders>
<!-- Async Loggers will auto-flush in batches, so switch off immediateFlush. -->
<RollingRandomAccessFile name="Appender1" fileName="servers/${sys:weblogic.Name}/logs/Auditing_${sys:weblogic.Name}.log" immediateFlush="true" append="false" filePattern="servers/${sys:weblogic.Name}/logs/archive/Auditing_${sys:weblogic.Name}-%d{yyyy-MM-dd-HH}-%i.log.gz">
<PatternLayout>
<Pattern>%d %p %c{1.} [%t] %m %ex%n</Pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy interval="1" modulate="true"/>
<SizeBasedTriggeringPolicy size="250 MB"/>
</Policies>
<DefaultRolloverStrategy max="20"/>
</RollingRandomAccessFile>
<Async name="Async1">
<AppenderRef ref="Appender1"/>
</Async>
</Appenders>
<Loggers>
<Logger name="examples.test.ABCImpl" level="info" includeLocation="false" additivity="false">
<AppenderRef ref="Appender1"/>
</Logger>
<Root level="info" includeLocation="false">
<AppenderRef ref="Appender1"/>
</Root>
</Loggers>
</Configuration>
The problem is even though the log file gets created, but nothing gets logged in it. The output in std out that I get is :
ABCImpl.initialize
activeHandlerEntries.length=1
***<Provider o/p follows> Before logger re-configuration:
Appenders:[Console]
***<Provider o/p follows> After logger re-configuration:
Appenders:[Async1, Appender1]
Just to make sure that my log4j2.xml and the piece of code is okay without runtime reconfiguration stuff, if I use -Dlog4j.configurationFile=file:SOME_PATH_OUTSIDE_JAR/log4j2.xml log gets populated as expected.
Please help.

I wondered, if deriving the context for initialization by
ctx = (LoggerContext) LogManager.getContext(false);
may be the problem, since you have to access the "current" context with
ctx = (LoggerContext) LogManager.getContext(true);
according to the Log4j2 API. I would really appreciate a clarification, since i'm trying to programmatically configuring Log4J2, too.

Hours of helpless staring at the code and trying my hands here and there, I found that if I get the Logger from newly initialized context (which is obtained from Configurator.initialize) instead of LogManager, log gets populated with data.
Without this trick, not sure if I needed to call any additional API methods (just after Configurator.initialize) to hook the new context into LogManager so that I could have continued traditional approach of getting Logger from LogManager.
...
config = (Configuration) ctx.getConfiguration();
mp = config.getAppenders();
System.out.println("***<Provider o/p follows> After logger re-configuration:");
System.out.println("\tAppenders:" + mp.keySet());
//reconfiguration attempt - ends
//Following line screwed me up for over three weeks
//logger = LogManager.getLogger(this.getClass().getName());
//workaround:
logger = ctx.getLogger(this.getClass().getName());
}
public void myBusinessMethod(){
logger.info("Entry..............");
logger.info("Exit..............");
}
....
}

Related

Dynamically get handle to logger and log msg in Log4J2

I am trying to programmatically create Log4J2 logger that can be used to log the messages to different files based on the logger name. Below is the method that I have created to log messages dynamically to named file. Files are getting created dynamically but message is not being logged to the created files.
public static synchronized Logger getLogger(String name) {
if (!LogManager.exists(name)) {
LoggerContext lc = (LoggerContext) LogManager.getContext();
Configuration config = lc.getConfiguration();
Appender app = rollingFileAppender(name);
config.addAppender(app);
AppenderRef ref = AppenderRef.createAppenderRef(name, INFO, null);
AppenderRef[] refs = new AppenderRef[]{ref};
LoggerConfig loggerConfig = LoggerConfig
.createLogger(true,INFO, name,"true",refs,null,config,null);
config.addLogger(name, loggerConfig);
config.start();
lc.updateLoggers(config);
// if I comment the method, then msg gets logged to all files that was created dynamically.
//lc.getRootLogger().addAppender(app);
lc.start();
}
return LogManager.getLogger(name);
}
Below is the File Appender that I have created, which is used to create logger.
private static Appender rollingFileAppender(String name) {
LoggerContext ctx = (LoggerContext) LogManager.getContext();
Configuration config = ctx.getConfiguration();
DefaultRolloverStrategy strategy = DefaultRolloverStrategy.newBuilder()
.withMax("20").withMin("1").withFileIndex("max")
.withConfig(config)
.withCompressionLevelStr(String.valueOf(Deflater.NO_COMPRESSION))
.build();
PatternLayout layout = PatternLayout.newBuilder()
.withConfiguration(config)
.withPattern("%d{yyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n")
.build();
String logPath = "C:\\Development\\log4J_test\\";
RollingFileAppender rfa = RollingFileAppender
.newBuilder()
.withFileName(logPath + name + ".log")
.withFilePattern(logPath + "/archive/$${date:yyyy-MM}/" + name + "-%d{MM-dd-yyyy}-%i.log.zip")
.withName(name)
.withLayout(layout)
.withPolicy(CompositeTriggeringPolicy.createPolicy(
TimeBasedTriggeringPolicy
.newBuilder()
.withInterval(1)
.withModulate(false)
.build(), SizeBasedTriggeringPolicy.createPolicy("25 MB")
)
).withStrategy(strategy)
.build();
rfa.start();
return RFA;
}
When I run the main method, file1 and file2 are getting created but no msg is being logged.
public static void main(String[] args) {
try {
Properties props = System.getProperties();
props.setProperty("log4j.configurationFile", "<location>\log4j2.xml");
Logger log = getLogger("file1");
log.info("Test log to file1");
log = getLogger("file2");
log.info("Test log to file2");
} catch (Exception e) {
e.printStackTrace();
}
}
Log4J Config file that I have created. Messages are getting logged to mainFile.log
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="DEBUG">
<Appenders>
<RollingFile name="main_log" fileName="C:\\log4J_test\mainFile.log"
filePattern="C:\\log4J_test\archive\${date:yyyy-MM}\EFDL-%d{MM-dd-yyyy}-%i.log.gz">
<PatternLayout>
<Pattern>"%d{yyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"</Pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy/>
<SizeBasedTriggeringPolicy size="25 MB"/>
</Policies>
<DefaultRolloverStrategy max="40"/>
</RollingFile>
</Appenders>
<Loggers>
<Root level="debug">
<AppenderRef ref="main_log" />
</Root>
</Loggers>
</Configuration>

log4j2, CWE 117 - log injection vulnerability

I've been trying to handle security of log4j2 in our spring application to pass in Veracode. Especially CWE 117 - log injection vulnerability.
We have a spring application with spring-boot-starter-log4j2. I have tried to configure log4j2 pattern:
<PatternLayout pattern="%d{DEFAULT} [%t] %-5level %logger{36} - %encode{%m}%n" />
but it doesn't work.
I also tried something like this:
<PatternLayout pattern="%d{ISO8601} %-5p - %encode{ %.-500m }{CRLF}%n" />
or
<PatternLayout pattern="%d{HH:mm:ss.SSS} %marker [%t] %-5level %logger{36} - %encode{%msg}{CRLF}%n"/>
I am still getting the veracode result:
117 Improper Output Neutralization for Logs WelcomeResource.java: 15
117 Improper Output Neutralization for Logs WelcomeResource.java: 16
We don't want use ESAPI nor any log facade, we don't want to change all log rows in our code, there are thousands of occurrences.
We would like to use the straigt setting as in the snippet below or here:
https://owasp.org/www-project-cheat-sheets/cheatsheets/Injection_Prevention_Cheat_Sheet_in_Java.html#Log_Injection
or
https://github.com/javabeanz/owasp-security-logging/wiki/Log-Forging
But it doesn't work. Where could be the problem?
Here is a snippet of our code:
build.gradle:
plugins {
id 'org.springframework.boot' version '2.2.0.RELEASE'
id 'io.spring.dependency-management' version '1.0.8.RELEASE'
id 'java'
id 'maven'
}
group = 'com.example'
version = '0.0.2-SNAPSHOT'
repositories {
mavenCentral()
}
configurations {
all {
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'
}
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-log4j2'
}
App.java:
package com.example.demoLog4j2;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class App {
final static org.slf4j.Logger Logger = LoggerFactory.getLogger("App");
public static void main(String[] args) {
SpringApplication.run(App.class, args);
System.out.println(" //---------------------->> DemoLog4j2 Application started... ");
Logger.info(" Logger implementation: " + Logger.getClass().getName());
}
}
WelcomeResource.java:
package com.example.demoLog4j2;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
#RestController
public class WelcomeResource {
private static final String welcomeMessage = "Welcome...";
final org.slf4j.Logger Logger = LoggerFactory.getLogger(this.getClass());
#GetMapping("/name")
public String getName(#RequestParam(name="name", required = false, defaultValue = "Josef") String name) {
Logger.info( "----- name: " + name);
Logger.debug( "--- name: " + name );
return "name: " + name;
}
}
log4j2.xml:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO ">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<!-- <PatternLayout pattern="%d{DEFAULT} [%t] %-5level %logger{36} - %encode{%m}%n" /> -->
<!-- <PatternLayout pattern="%d{HH:mm:ss.SSS} %marker [%t] %-5level %logger{36} - %encode{%msg}{CRLF}%n" /> -->
<PatternLayout pattern="%d{ISO8601} %-5p - %encode{ %.-500m }{CRLF}%n" />
</Console>
</Appenders>
<Loggers>
<Root level="INFO">
<AppenderRef ref="Console" />
</Root>
</Loggers>
</Configuration>
Finally we have solved the logging injection threat with "%encode{%msg}" in log4j2 config file. It solved the threat, but it didn't solve the veracode report. We ignored it, because it was false report. I don't know if veracode repaired it.

Log4j2: Log ERROR level into a specific file

In my log4j2 configuration, I have an AsyncRoot set to INFO because I want to log this level and upper in a file.
But I would like also to log the ERROR level into a specific file AND in the appender configured in the AsyncRoot
Here is my configuration:
<?xml version="1.0" encoding="utf-8"?>
<Configuration>
<Appenders>
<RollingFile name="file" fileName="${LOG_PATH}/${APP_NAME}.log" filePattern="${LOG_PATH}/${APP_NAME}-${FILE_PATTERN_TRAILER}.log">
<PatternLayout pattern="${PATTERN_LAYOUT}"/>
<Policies>
<SizeBasedTriggeringPolicy size="50 MB"/>
<TimeBasedTriggeringPolicy/>
</Policies>
<DefaultRolloverStrategy max="5"/>
</RollingFile>
<RollingFile name="errorFile" fileName="${LOG_PATH}/${APP_NAME}-errors.log" filePattern="${LOG_PATH}/${APP_NAME}-errors-${FILE_PATTERN_TRAILER}.log">
<PatternLayout pattern="${PATTERN_LAYOUT}"/>
<Policies>
<TimeBasedTriggeringPolicy/>
</Policies>
</RollingFile>
</Appenders>
<Loggers>
<AsyncRoot level="INFO">
<AppenderRef ref="file"/>
</AsyncRoot>
<AsyncLogger level="ERROR">
<AppenderRef ref="errorFile"/>
</AsyncLogger>
</Loggers>
</Configuration>
Here is the logging behaviour I'd like to achieve (no matter the package) :
All the logs with INFO log level are logged into the appender file
All the logs with ERROR log level are logged into the appender file and errorFile
All the logs with a lower log level (DEBUG, TRACE) aren't logged at all
Thank you
You can achieve what you want by setting the root logger's level to info since you don't want any trace or debug events to reach your appenders. Set the level on the error file appender to error so that only events of that level or more specific are written to the file.
Here's a simple example that you can adapt to your needs:
Java class to generate some log events
package example;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class SomeClass {
private static final Logger log = LogManager.getLogger();
public static void main(String[] args){
log.debug("This is some debug!");
log.info("Here's some info!");
log.error("Some error happened!");
}
}
log4j2 XML config file
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<File name="ErrorFile" fileName="logs/errors.log" immediateFlush="false"
append="false">
<PatternLayout
pattern="%d{yyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
</File>
<File name="InfoFile" fileName="logs/Info.log" immediateFlush="false"
append="false">
<PatternLayout
pattern="%d{yyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
</File>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="InfoFile" />
<AppenderRef ref="ErrorFile" level="error" />
</Root>
</Loggers>
</Configuration>
This generates 2 files: errors.log and Info.log
The error log contains only the error:
2019-12-04 10:05:34.672 [main] ERROR example.SomeClass - Some error happened!
The info log contains the info and error events:
2019-12-04 10:05:34.670 [main] INFO example.SomeClass - Here's some info!
2019-12-04 10:05:34.672 [main] ERROR example.SomeClass - Some error happened!
To do similar thing in the properties config file you can set config file as below
status = error
name = PropertiesConfig
filters = threshold
filter.threshold.type = ThresholdFilter
filter.threshold.level = debug
appenders = rolling, rollingErrorFile
appender.rolling.type = RollingFile
appender.rolling.name = RollingFile
appender.rolling.fileName = logs.log
appender.rolling.filePattern = logs.log.%i
appender.rolling.layout.type = PatternLayout
appender.rolling.layout.pattern = %d{ISO8601} %-5p %30.30c{2} : %m%n
appender.rolling.policies.type = Policies
appender.rolling.policies.size.type = SizeBasedTriggeringPolicy
appender.rolling.policies.size.size=20 MB
appender.rolling.strategy.type = DefaultRolloverStrategy
appender.rolling.strategy.max = 20
appender.rollingErrorFile.type = RollingFile
appender.rollingErrorFile.name = RollingErrorFile
appender.rollingErrorFile.fileName = logsErrors.log
appender.rollingErrorFile.filePattern = logsErrors.log.%i
appender.rollingErrorFile.layout.type = PatternLayout
appender.rollingErrorFile.layout.pattern = %d{ISO8601} %-5p %30.30c{2} : %m%n
appender.rollingErrorFile.policies.type = Policies
appender.rollingErrorFile.policies.size.type = SizeBasedTriggeringPolicy
appender.rollingErrorFile.policies.size.size=20 MB
appender.rollingErrorFile.strategy.type = DefaultRolloverStrategy
appender.rollingErrorFile.strategy.max = 20
loggers = rolling
#Make sure to change the package structure as per your application
logger.rolling.name = example
logger.rolling.level = debug
logger.rolling.additivity = false
logger.rolling.appenderRef.rolling.ref = RollingFile
logger.rolling.appenderRef.rollingErrorFile.ref = RollingErrorFile
logger.rolling.appenderRef.rollingErrorFile.level = error

BroadcastReceiver Not Firing after boot

Unable to get my Xamarin.Android app to fire Toast after boot. I checked many accepted solutions but none seem to resolve my problem. I've also tried various "working" examples but haven't had any luck so clearly I'm missing something.
Device: Samsung Galaxy S3
API: 19
Android Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.novak" android:versionCode="1" android:versionName="1.0" android:installLocation="auto">
<uses-sdk android:minSdkVersion="16" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application android:label="ReceiverApp">
<receiver android:enabled="true"
android:exported="true"
android-permission="android.permission.RECEIVE_BOOT_COMPLETED"
android:name="com.novak.BootReceiver" >
<intent-filter >
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
</application>
</manifest>
BootReceiver.cs
using Android.App;
using Android.Widget;
using Android.Content;
namespace ReceiverApp
{
[BroadcastReceiver]
[IntentFilter(new[] { Intent.ActionBootCompleted })]
public class BootReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
Toast.MakeText(context, "Receiver", ToastLength.Long).Show();
}
}
}
It would appear that what I want to do is not possible. Once my app is installed the app sits in a stopped state and must be executed manually the first time before it can receive broadcasts
[How to start a Service when .apk is Installed for the first time
P.S: On real device it takes a while to fire the event, ie: 2 minutes after unlock the screen on my Samsung. On emulator it takes very short.
I wrote the code below to notice when it will fire:
Autorun.cs - Just add this file into your project, that's it, it will start after the boot. No manifest modification needed.
using Android;
using Android.App;
using Android.Content;
// we need to ask permission to be notified of these events
[assembly: UsesPermission (Manifest.Permission.ReceiveBootCompleted)]
namespace XamarinCookbook
{
// we want this to fire when the device boots
[BroadcastReceiver]
[IntentFilter (new []{ Intent.ActionBootCompleted })]
public class ServiceStarter : BroadcastReceiver
{
public override void OnReceive (Context context, Intent intent)
{
#region Start chrome
var mesaj = "Autorun started";
Android.Widget.Toast.MakeText(Android.App.Application.Context, mesaj, Android.Widget.ToastLength.Long).Show();
var uri = Android.Net.Uri.Parse("https://500px.com");
var intent1 = new Intent(Intent.ActionView, uri);
intent1.AddFlags(ActivityFlags.NewTask);
intent1.SetPackage("com.android.chrome");
try
{
context.StartActivity(intent1);
}
catch (ActivityNotFoundException ex)
{
//Chrome browser not installed
intent.SetPackage(null);
context.StartActivity(intent1);
}
#endregion
/*
#region Real code
// just start the service
var myIntent = new Intent (context, typeof(XamarinService));
context.StartService (myIntent);
#endregion
*/
}
}
}
VS Solution:
https://drive.google.com/open?id=1iYZQ2YCvBkyym9-2FvU7KXoBKUWsMdlT

PersistenceManager issue

I have written a code to save my screen data and retrieve it for second time. Code is:
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
title="HomeView"
add="addHandler(event)">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
import spark.managers.PersistenceManager;
protected function saveButton_clickHandler(event:MouseEvent):void
{
var saveManager:PersistenceManager = new PersistenceManager();
saveManager.setProperty("myText", myInput.text);
}
protected function addHandler(event:FlexEvent):void
{
var loadManager:PersistenceManager = new PersistenceManager();
if(loadManager.load())
{
var savedData:Object = loadManager.getProperty("myText");
if(savedData)
myInput.text = savedData.toString();
}
}
protected function clearButton_clickHandler(event:MouseEvent):void
{
var persistenceManager:PersistenceManager = new PersistenceManager();
persistenceManager.clear();
myInput.text = "";
}
]]>
</fx:Script>
<s:TextInput width="100%" id="myInput"/>
<s:Group width="100%">
<s:layout>
<s:HorizontalLayout/>
</s:layout>
</s:Group>
<s:Button id="saveButton" x="-1" y="65" width="100%" label="Save"
click="saveButton_clickHandler(event)"/>
<s:Button id="clearButton" x="0" y="116" width="100%" label="Clear"
click="clearButton_clickHandler(event)"/>
But, when I packaging it for deploying on iPad, it gives me a error like:
Error occurred while packaging the application:
Error occurred during initialization of VM
Could not reserve enough space for object heap
Could not create the Java virtual machine.
Compilation failed while executing : ADT
I am using Flash builder 4.5 to create iOS application.
Thanx in advance
You need to modify your FlashBuilder.ini file
It's located in your FlashBuilder installation directory.
You need to modify the Xms size - this will allocate more memory while compiling and building project. Remember it should be in strongs of 2.
My file looks like this:
launcher.defaultAction
openFile
-nl
en_US
-vmargs
-Xms256m
-Xmx512m
-XX:MaxPermSize=256m
-XX:PermSize=64m

Resources