24

I want to be able to use different log4j configuration for different environments.

In my development environment, I want to use log4j.properties (A). But when I build in Maven for the production environment, I want to use log4j.properties (B).

Please tell me how to configure this in my pom.xml?

Jawher
  • 6,937
  • 1
  • 17
  • 12
Kedron
  • 343
  • 1
  • 3
  • 9
  • Do you use maven-release-plugin manage production build? – yorkw Mar 03 '12 at 04:59
  • No, I'v never heart of maven-release-plugin before. Still Thanks, I will find if it can deal with the problem. – Kedron Mar 03 '12 at 08:15
  • 7
    This is a quiet recurring question and I would like to add my two cents. Creating multiple builds for different environment is often not accepted by a client. They want ONE build for all the environments to eliminate any regression problems with multiple builds. The log4j file should be declared outside of your application as are any any environment specific variables. The philosophy 'build once deploy anywhere' seems to always get lost with maven build profiles. – tom Mar 03 '12 at 08:34
  • @tom I'm keen to improve how to do one build for all environments. My idea of it is a certain execution of our build server builds artifacts for all regions/environments before it's done. My problem with what you said is excluding the environment specific variables - our packaged artifacts should be complete and ready to deploy shouldn't they? – Crowie Sep 25 '13 at 08:39
  • @Crowie Our artifacts are ready to deploy but there is always a per environment configuration file being it a log4j file or a properties file. These files are configured outside the application artifact but within the application server. – tom Sep 25 '13 at 09:02
  • @tom fair enough. doing a bit of googling around, found [this](http://stackoverflow.com/q/4932944/977087) question about *building multiple profiles in one go* and Sean Patrick Floyd responding 'This does not fit into the maven lifecycle. So what you will need to do is to cause some external process to do the iteration and call maven repeatedly with different parameters.' I'd prefer to do that - and use profiles to do one build to generate many artifacts. Seems less risky for me – Crowie Sep 25 '13 at 09:52

6 Answers6

11

You can use profiles to achieve the desired behavior:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-resources-plugin</artifactId>
            <version>2.5</version>
            <executions>
                <execution>
                    <id>log4j</id>
                    <phase>process-resources</phase>
                    <goals>
                        <goal>copy-resources</goal>
                    </goals>
                    <configuration>
                        <outputDirectory>output_directory</outputDirectory>
                        <resources>
                            <resource>${log4j.file}</resource>
                        </resources>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

<profiles>
    <profile>
        <id>dev</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <properties>
            <log4j.file>path_to_file_A</log4j.file>
        </properties>
    </profile>
    <profile>
        <id>prod</id>
        <properties>
            <log4j.file>path_to_file_B</log4j.file>
        </properties>
    </profile>
</profiles>
Crowie
  • 3,220
  • 7
  • 28
  • 48
Andrew Logvinov
  • 21,181
  • 6
  • 52
  • 54
8
1. in your project add 3 folders : 

  Your Project\src\main\resources\

            \A > log4j.properties
            \B > log4j.properties
            \Default > log4j.properties
2. in pom.xml         

       <properties>
                <param>Default</param> 
        </properties>

        <build>
            <resources>
                <resource>
                    <directory>src/main/resources/${param}</directory>           
                </resource>
            </resources>
        </build> 

3. 

 - if : mvn clean install : classpath => log4j.properties(Default)

 - if : mvn clean install  -Dparam=A : classpath => log4j.properties(A)

 - if : mvn clean install  -Dparam=B : classpath => log4j.properties(B)


> much better than using profiles is more extensible without touching the pom
question_maven_com
  • 2,457
  • 16
  • 21
4

You don't need the maven-resources-plugin if you have a simple environment.

In this example, log4j.properties B is the file you use for production and is in the directory src/main/java and log4j.properties A is the file you use for development and is in the directory /Users/junger/.m2/.

In your pom.xml:

<properties>
    <log4j.properties.directory>src/main/java</log4j.properties.directory>
</properties>

<build>
    <resources>
        <resource>
            <directory>${log4j.properties.directory}</directory>
            <includes>
                <include>log4j.properties</include>
            </includes>
        </resource>
    </resources>
</build>

Now, in your /Users/junger/.m2/settings.xml (create one if it doesn't exist):

<profiles>
    <profile>
        <id>dev</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <properties>
            <log4j.properties.directory>/Users/devuser/.m2/</log4j.properties.directory>
        </properties>
    </profile>
</profile>

By using this method, each developer can have a different log4j.properties directory and you keep your pom.xml clean.

Josh Unger
  • 6,717
  • 6
  • 33
  • 55
3

Simplest way for me,

  • Define a system variable ENV and set its value _dev for your development env.
  • Where you refer this file use like this log4j${ENV}.properties

So,

In production it simply use log4j.xml and for your dev log4j_dev.xml

  • In order to prevent problems it would be better to create also ENV variable for production as _pro so for production log4j_pro.xml, for dev log4j_dev.xml will be used.

I believe that relying on different files than copying resource is better practice.

Cemo
  • 5,370
  • 10
  • 50
  • 82
2

There is a very simple solution good for small projects with jar packaging (I haven't tested it on war packaged projects). The only disadvantage is that you have to duplicate all resources, but if your only resource is log4j.properties this is not a problem.

If you have a directory tree like this:

log4j.properties maven profile project structure
...

enter image description here

You should have the following pom:

<build>
    <finalName>${project.artifactId}</finalName>
    <sourceDirectory>src/</sourceDirectory>
    <resources>
        <resource>
            <directory>${resources.path}</directory>
        </resource>
    </resources>
</build>

<profiles>
    <profile>
        <id>default</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <properties>
            <resources.path>resources/prod</resources.path>
        </properties>
    </profile>
    <profile>
        <id>dev</id>
        <activation>
            <activeByDefault>false</activeByDefault>
        </activation>
        <properties>
            <resources.path>resources/dev</resources.path>
        </properties>
    </profile>
</profiles>

Then when you use dev profile log4j.properties from resources/dev is used. When you use any other profile or no profile at all then log4j.properties from resources/prod is used. So your *.jar should look like this:

log4j.properties maven profile project jar directory structure
Of course if you have different resources location, for example main/java/resources/..., you should specify it instead of resources/...

luke
  • 3,435
  • 33
  • 41
1

To some extent you can reference environment variables inside a log4j.properties to add environment dependent behavior. e.g.

log4j.rootLogger=${rootLoggerLevel}, ${appender}
mjj1409
  • 3,075
  • 6
  • 28
  • 28