I am newbie to implement log4j2 with my aws java lambda cloud watch. I need custom log instead of cloud watch logs. I am uploading a csv of large size record using step function.So the built in cloud watch logs the same thing repeatedly. So I am planning to add log4j2 with my java lambda. For this I added below dependency in my pom.xml
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-log4j2</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.8.2</version>
</dependency>
Then added the log4j2.xml under src/main/resources. The log4j2.xml is like below
<?xml version="1.0" encoding="UTF-8"?>
<Configuration packages="com.amazonaws.services.lambda.runtime.log4j2.LambdaAppender">
<Appenders>
<Lambda name="Lambda">
<PatternLayout>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %X{AWSRequestId} %-5p %c{1}:%L - %m%n</pattern>
</PatternLayout>
</Lambda>
</Appenders>
<Loggers>
<Root level="debug">
<AppenderRef ref="Lambda" />
</Root>
</Loggers>
</Configuration>
After that to check the log i have created one aws java lambda project and my code looks like below.
package com.amazonaws.lambda.demo;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.S3Event;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.GetObjectRequest;
import com.amazonaws.services.s3.model.S3Object;
import com.amazonaws.services.stepfunctions.AWSStepFunctions;
import com.amazonaws.services.stepfunctions.AWSStepFunctionsClientBuilder;
import com.amazonaws.services.stepfunctions.model.StartExecutionRequest;
import com.amazonaws.services.lambda.runtime.Context;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class log4jTest implements RequestHandler<S3Event, String> {
static final Logger logger = LogManager.getLogger(log4jTest.class);
private AmazonS3 s3 = AmazonS3ClientBuilder.standard().build();
public log4jTest() {}
log4jTest(AmazonS3 s3) {
this.s3 = s3;
}
#Override
public String handleRequest(S3Event event, Context context) {
String bucket = event.getRecords().get(0).getS3().getBucket().getName();
String key = event.getRecords().get(0).getS3().getObject().getKey();
try {
for(int i=0;i<10;i++)
{
if(i==10)
{
logger.error("log data Error");
}
}
} catch (Exception e) {
context.getLogger().log(String.format(
"Error getting object %s from bucket %s. Make sure they exist and"
+ " your bucket is in the same region as this function.", key, bucket));
}
return null;
}
}
According to the aws document Logging (Java).
Everything I did as the doc says. But when I am run the lambda I am getting an error like below
ERROR StatusLogger No log4j2 configuration file found. Using default configuration: logging only errors to the console. Set system property 'org.apache.logging.log4j.simplelog.StatusLogger.level' to TRACE to show Log4j2 internal initialization logging.
I am checking the log in lambda -> Monitoring -> jump to logs [Screen shot given below]
I googled and went through below sites.
No log4j2 configuration file found. Using default configuration: logging only errors to the console
No log4j2 configuration file found. Using default configuration: logging only errors to the console
But I dont know I can't fix this error anyway. Please anyone can help me on this. It would be really grateful if u can do this.
Thanks in advance
I found I did not have any luck placing my log4j2.xml file at either src/main/resources or at src/main/resources/path/to/my/Lambda/log4j2.xml.
So I did a little digging. In my case, Lambda deploys my handler with a classpath whose first entry is a folder /var/task. The class files are rooted directly at /var/task - but the resource files are placed in /var/task/resources - so Log4J2 cannot find log4j2.xml in the classpath. The solution for me was to use the log4j.configurationFile property to specify the location of the file within the resources folder:
static {
// System.setProperty("org.apache.logging.log4j.simplelog.StatusLogger.level","TRACE");
System.setProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager");
System.setProperty("log4j.configurationFile", "resources/lambda-log4j2.xml");
}
I also renamed the file "lambda-log4j2.xml" - to make sure it was reading my file, during debugging this...
This static block is at the top of my handler class.
Related
I'm using log4j2 and splunk within java to send logs into my Splunk Enterprise HEC (HTTP Event Collector) Splunk Enterprise is running in my local machine.
I'm doing all log4j2 configuration programmatically. (I know this is not the correct way to do this but I'm still doing this for learning purpose).
I tried to send the logs into Splunk Enterprise directly from postman with the same URL and token and it works fine, but when I tried to send the logs from java using log4j2 I don't get anything in splunk.
My code is =>
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.config.Configurator;
import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory;
import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
import org.apache.logging.log4j.core.layout.PatternLayout;
import com.splunk.logging.*;
public class Main {
private static final Logger log;
static {
configureLog4J();
log = LogManager.getLogger(Main.class);
}
public static void configureLog4J() {
ConfigurationBuilder<BuiltConfiguration> builder =
ConfigurationBuilderFactory.newConfigurationBuilder();
// configure a splunk appender
builder.add(
builder.newAppender("splunkH", "SplunkHttp")
.add(
builder.newLayout(PatternLayout.class.getSimpleName())
.addAttribute(
"pattern",
"%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"
)
)
.addAttribute("sourcetype", "log4j2")
.addAttribute("index", "main")
.addAttribute("url", "http://localhost:8088/services/collector") //I tried this url in postman and its working fine there
.addAttribute("token", "xxx")
.addAttribute("disableCertificateValidation", "true")
);
// configure the root logger
builder.add(
builder.newRootLogger(Level.INFO)
.add(builder.newAppenderRef("splunkH"))
);
// apply the configuration
Configurator.initialize(builder.build());
}//end of configureLog4J
public static void main(String ar[]) {
log.log(Level.INFO, "Hello from log4j2");
log.log(Level.ERROR, "Error from log4j2");
}//end of main method
}//end of class
my POM file
<dependencies>
<dependency>
<groupId>com.splunk.logging</groupId>
<artifactId>splunk-library-javalogging</artifactId>
<version>1.11.4</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.11.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.11.2</version>
</dependency>
<dependency>
<groupId>com.splunk</groupId>
<artifactId>splunk</artifactId>
<version>1.6.5.0</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>splunk-artifactory</id>
<name>Splunk Releases</name>
<url>https://splunk.jfrog.io/splunk/ext-releases-local</url>
</repository>
</repositories>
I cannot see any logs in splunk. Did I miss something ?
Add .addAttribute("batch_size_count", "1") or make a loop producing 10 log messages, becasue that's the default value of batch_size_count. This has been explained in splunk docs "Configure Log4j 2" section.
By the way, I reckon the services/collector endpoint should be used with JSON messages (e.g. .add(builder.newLayout("JSONLayout"))). Also, you are using a log4j2 version that has the Log4Shell (CVE-2021-44228) vulnerability. It has been fixed in 2.15.0, switch to anything between that and the newest version 2.17.2.
Finally, I share the sentiment of the answers to the question How to configure log4j 2.x purely programmatically? that log4j2 is troublesome to use when configured programmatically. I had issues with it in a cluster env and switching to file configuration solved all my problems.
My log4j does not record any log file. I am not sure if this is a problem from the settings inside log4j.properties or the location of this file.
The way I built the project:
git clone https://github.com/spring-guides/gs-maven.git
Then modified: .\initial\pom.xml and added support for log4j:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-bom</artifactId>
<version>2.17.2</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
</dependency>
</dependencies>
just before:
</project>
Added log commands to .\initial\src\main\java\hello\HelloWorld.java as follows:
package hello;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class HelloWorld {
private static Logger logger = LogManager.getLogger(HelloWorld.class);
public static void main(String[] args) {
logger.error("Application status : {} ", "start");
Greeter greeter = new Greeter();
System.out.println(greeter.sayHello());
logger.error("Application status : {} ", "terminated");
}
}
Then added log4j.properties:
appender.stdout.type = Console
# ... other appender properties
appender.file.type = File
# ... other appender properties
logger.app = INFO, stdout, file
# logger.app.name = com.example.app
# is equivalent to:
# appender.stdout.type = Console
# appender.stdout.name = stdout
# ...
appender.file.type = File
appender.file.name = mylog
# ...
# logger.app.name = com.example.app
logger.app.level = INFO
logger.app.appenderRef.$1.ref = stdout
logger.app.appenderRef.$2.ref = file
I kept changing the location of this file to
.\initial\log4j.properties
.\initial\target\log4j.properties
.\initial\target\classes\log4j.properties
.\initial\target\classes\hello\log4j.properties
None of them have ever worked at all. I do not see mylog or any other log files.
The way I run the project is as follows:
cd initial
mvn compile
mvn package
java -jar target/gs-maven-0.1.0.jar
How should I fix this?
There are some problems with your configuration:
As Gopinath remarked, the configuration file should be in src/main/resources. Maven will copy it to target/classes,
Log4j 1.x uses the name log4j.properties, Log4j 2.x uses log4j2.properties,
The properties configuration format is the most difficult to master. I would advise you to use any of the other format (e.g. XML, which does not require additional dependencies).
If you insist on using the properties format, here are some hints:
every configuration requires a root logger, which is the ancestor of each logger and provides the default values for the other logger configurations. You can use the shorthand notation:
rootLogger = INFO, stdout, file
introduced in version 2.17.2 or the long notation:
rootLogger.level = INFO
rootLogger.appenderRef.$1.ref = stdout
rootLogger.appenderRef.$2.ref = file
The names of the appender references must match the name properties of the appenders:
appender.stdout.name = stdout
appender.file.name = file
there is no shorthand for that.
The FileAppender needs a fileName:
appender.file.fileName = mylog
I am trying to write to my webapp logs to a .log file in the /logs directory in tomcat but the file is not generated nor is any logging output going to the console other than the spring logs and tomcat logs. When I run spring boot as a jar file with the embedded tomcat it writes to the log file just fine, but as soon as I deploy to tomcat via the webapps folder the application logs are no where to be found.
SpringBoot 2.1.2
Java 1.8
Tomcat 8.5
I have tried:
configuring LOGGING_CONFIG in setenv.sh
Multiple loggers.. logback, java utils etc..
application.properties:
logging.file=../logs/my-app.log
logging.level.org.springframework=INFO
logging.level.com.bose=DEBUG
log4j.properties for log4j:
log4j.rootLogger=${marge.log.level}, stdout, file
# Direct log messages to a log file
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=marge.log
#when stdout is also specified it will not write to the file
log4j.appender.file.MaxFileSize=1MB
# Keep one backup file
log4j.appender.file.MaxBackupIndex=1
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{dd MMM yyyy HH:mm:ss,SSS} [%c] [%-5p] %n%m%n
# Direct log messages to stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
# stdout uses PatternLayout
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss,SSS} [%c] [%-5p] %n%m%n
# Print only messages of level DEBUG or above in the package com.bose
log4j.logger.com.app=${log.level}
Expected: when I deploy my webapp in /webapps the application logs (generated by log4j) should be in my-app.log in the /logs directory
Actual: No file is generated and no logs are even in stdout/console
By default spring boot uses logback as a logging binder, so the key concept here to exclude logback first then include log4j
Example:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
After that add log4j 2 dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
Add your log4j2.properties file to src/main/resources to be on classpath
Finally pay attention to what logging interface you are using this is important, with the above configuration you should use apache logging like:
package com.example;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.ApplicationContext;
#SpringBootApplication
public class Application extends SpringBootServletInitializer {
private static final Logger LOGGER = LogManager.getLogger(Application.class);
public static void main(String[] args){
ApplicationContext ctx = SpringApplication.run(Application.class, args);
LOGGER.info("Info level log message");
LOGGER.debug("Debug level log message");
LOGGER.error("Error level log message");
}
}
I have a Maven project with Java 9 and am using modules. Logback seems to support this since version 1.3.0-alpha1 but unfortunately I didn't got it to work.
I get the following message from SLF4J:
SLF4J: No SLF4J providers were found.
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#noProviders for further details.
It looks like it can't find Logback. And inspecting the (by Jlink generated) artifact using jimage list .../modules I can't find anything about logback apart my logback.xml configuration file.
Maybe the problem lies in my module-info.java:
open module my.super.app {
requires jackson.annotations;
requires jdk.jsobject;
requires com.fasterxml.jackson.databind;
requires com.fasterxml.jackson.core;
requires javafx.graphics;
requires javafx.controls;
requires org.slf4j;
exports my.super.app;
}
How and where do I declare to depend on Logback using Java 9 modules?
Short answer: You declare it in your jlink-call by adding logback to the module path and using the --bind-services option. In your module you only define an usage of SLF4j.
Long answer:
I made it work in a simple example with the following parts.
Starting from version 1.8.0 SLF4J is modularized and uses the ServiceLoader mechanism to find its logging backend.
Logback-classic:1.3.0-alpha4 is modularized, too, and declares a service both in META-INF/services/org.slf4j.spi.SLF4JServiceProvider and in its module descriptor:
provides org.slf4j.spi.SLF4JServiceProvider with ch.qos.logback.classic.spi.LogbackServiceProvider;
SLF4J declares in its module descriptor that it needs a SLF4JServiceProvider:
uses org.slf4j.spi.SLF4JServiceProvider
Therefore, in my POM (see below) I only declare a runtime dependency to Logback and my module descriptor only contains a "requires" clause to SLF4J.
My module "com.github.gv2011.j9mod.loguse" contains a main class that logs a statement to a SLF4J-Logger.
Further, it contains a logback.xml configuration file as resource. This file is accessible to Logback because it is a "miscellaneous resource", which is a resource not in a module package (see BuiltinClassLoader source).
Logback must be added explicitely to the runtime image via the jlink "--bind-services" option (because it is a service implementation).
Additionally, Logback and its dependencies must be available on the modulepath (jlink "--module-path" option).
Module descriptor:
module com.github.gv2011.j9mod.loguse {
requires org.slf4j;
}
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>com.github.gv2011.j9mod</groupId>
<artifactId>j9mod-log-use</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.8.0-beta4</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.3.0-alpha4</version>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<release>11</release>
</configuration>
</plugin>
</plugins>
</build>
logback.xml:
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!-- "+++" just to make it obvious that this file is used: -->
<pattern>+++ %d{"yyyy-MM-dd'T'HH:mm:ss,SSSXXX", UTC} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="com.github.gv2011.j9mod.loguse.Main" level="INFO" />
<root level="WARN">
<appender-ref ref="STDOUT" />
</root>
</configuration>
Main-Class:
package com.github.gv2011.j9mod.loguse;
import static org.slf4j.LoggerFactory.getLogger;
import org.slf4j.Logger;
public class Main {
private static final Logger LOG = getLogger(Main.class);
public static void main(final String[] args) {
LOG.info("Tach.");
}
}
Output (Eclipse - Run As - Java Application):
+++ 2019-05-09T17:43:20,594Z [main] INFO com.github.gv2011.j9mod.loguse.Main - Tach.
jlink:
%JAVA_HOME%\bin\jlink.exe ^
--output target\image ^
--module-path ^
target\classes;^
%M2_REPO%\org\slf4j\slf4j-api\1.8.0-beta4\slf4j-api-1.8.0-beta4.jar;^
%M2_REPO%\ch\qos\logback\logback-classic\1.3.0-alpha4\logback-classic-1.3.0-alpha4.jar;^
%M2_REPO%\ch\qos\logback\logback-core\1.3.0-alpha4\logback-core-1.3.0-alpha4.jar ^
--bind-services ^
--launcher hello=com.github.gv2011.j9mod.loguse/com.github.gv2011.j9mod.loguse.Main ^
--add-modules com.github.gv2011.j9mod.loguse
Output (target/image/bin/hello):
+++ 2019-05-10T11:45:24,844Z [main] INFO com.github.gv2011.j9mod.loguse.Main - Tach.
Tested with openjdk-11.0.2_windows-x64, apache-maven-3.6.0 and eclipse-jee-2019-03-R-win32-x86_64 on Windows 10, 64 Bit.
I finally figured it out. At the end, I just added Logback as a dependency in my module-info.java:
open module my.super.app {
requires jackson.annotations;
requires jdk.jsobject;
requires com.fasterxml.jackson.databind;
requires com.fasterxml.jackson.core;
requires javafx.graphics;
requires javafx.controls;
requires org.slf4j;
requires ch.qos.logback.classic; //only runtime dependency
exports my.super.app;
}
I guess there is no way to declare a runtime dependency (similar to Maven) - it is now also required at compile time.
I am trying to run a standalone java program using log4j, but receiving below while debugging (with no log4j related logs on console):
log= {Logger#1343} "java.lang.Class:ERROR in 18b4aac2"
Can someone please suggest what is wrong here?
The code is as below:
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Logger;
import java.io.IOException;
import java.sql.SQLException;
public class log4jExample {
static org.apache.logging.log4j.Logger log = LogManager.getLogger(log4jExample.class.getClass());
public static void main(String[] args)throws IOException,SQLException {
System.out.println("in main...");
log.debug("Hello this is a debug message");
System.out.println("in main...2..");
log.info("Hello this is an info message");
}
}
And the log4j.properties file is as below which is kept at src/main/resources.
log4j.rootLogger=DEBUG, stdout, file
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=C:\\test\\log4j-example.log
log4j.appender.file.MaxFileSize=1MB
log4j.appender.file.MaxBackupIndex=2
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
I am running my java program with VM option
-Dlog4j.configurationFile=C:\MyFirstProject\src\main\resources\log4j.properties
It seems to me like you have mixed up log4j versions. The configuration file you use is using log4j 1.x format. You have to convert it to log4j 2.x format. I tried your example and it works. See details below.
pom.xml file
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.bft.</groupId>
<artifactId>test</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.7</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.7</version>
</dependency>
</dependencies>
</project>
Re-factored code
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class log4jExample {
static final Logger logger = LogManager.getLogger(log4jExample.class);
public static void main(String[] args) {
System.out.println("in main...");
logger.info("Hello this is a debug message");
System.out.println("in main...2..");
logger.info("Hello this is an info message");
}
}
log4j.properties file (in log4j2.x format)
status = error
dest = err
name = PropertiesConfig
filter.threshold.type = ThresholdFilter
filter.threshold.level = debug
appender.console.type = Console
appender.console.name = STDOUT
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = %m%n
rootLogger.level = info
rootLogger.appenderRef.stdout.ref = STDOUT
Output:
in main...
Hello this is a debug message
in main...2..
Hello this is an info message
Process finished with exit code 0
Refer the log4j docs.
It is not an error !
It just says that your logger level is set to ERROR, so you will not see the messages logged to DEBUG/INFO levels.
Maybe you should check if your configuration is compatible with Log4J-2.x:
https://logging.apache.org/log4j/2.x/manual/configuration.html#Properties
https://logging.apache.org/log4j/2.x/manual/appenders.html#ConsoleAppender
Use XML format is usually better.