how do you set up log4j for a gradle project with modules? - gradle

how do you set up log4j for a gradle project with modules?
I have a project set up like the following:
project root
build.gradle
gradle.properties
settings.gradle
// this root project does:
// include CommonModule
// includeBuild <all composite modules within module folder>
---CommonModule
------build.gradle
------gradle.properties
------settings.gradle
------src/main/groovy/...<common-code>
------src/main/resources/log4j2.xml
Modules
---OtherModule-1
// this is a gradle composite module
// it also includes the common module
------build.gradle
------gradle.properties
------settings.gradle
------src/main/groovy/...module1-code
------src/main/resources/log4j2.xml
---OtherModule-2
// this is a gradle composite module
// it also includes the common module
------build.gradle
------gradle.properties
------settings.gradle
------src/main/groovy/...module2-code
------src/main/resources/log4j2.xml
As shown above, we have a common gradle module and a module folder that contains module related composite module, each which depends on the included CommonModule
(core common code goes in common, the composite modules each contain code that extends common stuff
My question is hopefully simple:
where do I configure my log4j module?
e.g. can I put it in the common include module ?
or does each composite module need to have their own log4j xml?

I went and asked this same question on the gradle forums https://discuss.gradle.org/t/how-do-you-set-up-log4j-for-a-gradle-project-with-modules/28262 and got an answer -
Common module doesn’t include a log4j config Individual library
modules don’t include a log4j config either Top-level application
module does include a log4j config, but doesn’t put it on the
classpath (I set aside a src/[configuration]/config directory just
for that)
Launcher for the application itself (whether from a release
build or from a JavaExec in the Gradle build) specifies where the
log4j config is loaded from, so that you can’t get accidentally
poisoned by other configs on the classpath
you can define the xml location by providing a -D flag in the gradle properties file e.g. -Dlog4j.configurationFile=
also -Dlog4j.debug might help to track down issues

Related

import dependencies from another module

I think I am missing some point in how dependencies management works in gradle.
Let's say I have the following project structure:
project
---api
------api-commons
------api-v1
------api-v2
------api-v3
where all api* directories are modules. All api-v* need a particular dependency (let's say common-dependency).
My aim would be to import it in api-commons build.gradle file:
dependencies {
implementation 'common-dependency'
}
while in the build.gradle files of the other modules api-v* put:
dependencies{
implementation project(':api:api-commons')
}
I would expect this to work but it doesn't. The code in the api-v* modules simply acts like the dependency is not declared. Indeed, if I import the dependency in the single modules, the code works as expected.
Am I doing a wrong assumption? Doesn't the dependency inheritance work like that?
Declaring a dependency in the implementation configuration conceptually means it is internal to the module (it is used in the implementation but not part of the public API). Such a dependency will not be exposed to the compile classpath of consumers, though it will still be on the runtime classpath.
An advantage of this way of modelling dependencies is that you do not need to recompile consuming projects if an implementation dependency changes. Another is that by encapsulating them, it is less likely that a consumer will start depending on them directly and then breaking if you change them.
If you want to expose the dependency to consumers, you have to declare it as part of the API for the module. You do that by applying the java-library plugin and using the api configuration.
Example:
// api-commons/build.gradle
plugins {
id 'java-library'
}
dependencies {
api 'common-dependency'
}
Read more about it in the Gradle user guide
Let say, I have to moved below common code(*.java files) from below 2 service/modules to sharedprocessing-data which is present inside shared-libraries service/modules :
abc-service
xyz-servcie
Address.java
Employee.java
Department.java
Vaccation.java
Name.java
City.java
Order.java
Steps0:
In shared- service/modules folder create additional module inside existing shared-libraries module
Name it as sharedprocessing-data
Steps1:
Move(refactor) common code inside this module
Steps2:
In parent folder (root) update settings.gradle file
rootProject.name = "root"
include 'abc-service'
include 'xyz-service'
include 'shared-libraries:sharedprocessing-data'
Step3:
In each of abc-service and xyz-flow service modules, update build.gradle file
dependencies
{
implementation project(':shared-libraries:sharedprocessing-data')
}

Gradle test library in multi module project

I want to create a library that other modules in my project can depend on, but only for tests. I've read the Gradle documentation extensively and couldn't find how to do it. This is my project structure:
gradle-example:
app:
src/main/kotlin ...
src/test/kotlin <- this is supposed to use 'com.example.SomeTestUtil'
testlib:
src/test/kotlin/com.example.SomeTestUtil
settings.gradle.kts:
rootProject.name = "gradle-example"
include("app")
include("testlib")
In the app module I tried adding
dependencies {
testImplementation(project(:testlib"))
}
But I get compilation error trying to import the SomeTestUtil in the app module test classes.
What is the correct way to declare dependency on a module in the same project that allows to use test sources in test code?
To clarify, we want to create a library that can only be used by other modules under src/test and not src/main.
Apparently this can be done by using the https://docs.gradle.org/current/userguide/java_testing.html#sec:java_test_fixtures
they can see the main source set classes
test sources can see the test fixtures classes
So changes to the example in the question are:
changing the src/test to src/testFixtures
declaring the dependency as testImplementation(testFixtures(project(":testlib")))
Adding java-test-fixtures plugin to the build.gradle.kts for the testlib module

Gradle equivalent for maven properties

How can I add properties in Gradle which are similar to Maven's properties?
The use case is this: I want to have a file which declares all versions for repo dependencies so they are unified in a single place for a multi module project
compile group: 'javax.servlet.jsp.jstl', name: 'jstl', version: '1.2'
In Maven you can have properties like this:
<properties>
<jstlVersion>1.2</jstlVersion>
</properties>
Is it ok to use Gradle's external properties? Or just add them to the gradle.properties file?
Project properties defined in the root build file are available to subprojects. So if you have this in your root build.gradle file:
ext.commonsLangVersion = "2.4"
then you can use that in the dependencies {} block of a subproject like so:
dependencies {
implementation "commons-lang:commons-lang:${commonsLangVersion}"
}
You can also define such properties in the root gradle.properties file instead of the root build file. You use them in the same way.
If you really feel the need to put the versions in a separate file, you can do so. Simply add the following line to the root build file:
apply from: "dependencies.gradle"
Within the dependencies.gradle file, you can define the extra project properties as if they were in the root build file directly:
ext.commonsLangVersion = "2.4"
Note Normally, the values set in the build script take precedence over the values in gradle.properties. But if you set a value in the root build script as above, then any matching value in gradle.properties will override it in subprojects.
This behaviour is somewhat confusing and unique. For behaviour that is consistent with Gradle single-project builds you would need to use the following in the root build script:
allprojects {
apply from: "dependencies.gradle"
}
As a general rule of thumb, any given property should be declared/defined in either the build script or gradle.properties. If users want to override a particular property value, they can do so in $USER_HOME/.gradle/gradle.properties.
[EDIT I have updated the above note to clarify the actual behaviour]
One final thing: Gradle also allows you to control the versions of transitive dependencies via dependency constraints. You can also import Maven BOMs if you're using Gradle 4.6 or newer.
Found this as a possible solution, though I don't really like that uses relative path to the properties file.
Point 7 from here:
https://proandroiddev.com/make-your-build-gradle-great-again-c84cc172a654#8029

Setting dependency of a component to mantle-usl - custom Groovy class

I have a custom groovy class inside mantle-usl component. I would like to use the class in other component. Hence, I need to add a dependency so that the new component (or project) has the jar of mantle-usl ready for use.
Is there anyone who can help with this? I attempted to modify the build.gradle file of the project. And add a project dependency, but it returned an error.
project(':runtime/component/warehouse-items-masterenumerator') {
dependencies {
compile project(':runtime/component/mantle-usl')
}
}
As you would expect, this does not work. It seems that I do not have the project references set correctly.
The mantle-usl component doesn't have any compiled code in it so the build.gradle file does not build a jar file, it is only used for running the Spock tests.
I wouldn't recommend adding your own code to mantle-usl, it is easier and cleaner to put it in a separate component. For an example of a build.gradle file that does build a jar file look at the moqui/example component or most of the moqui tool components (such as moqui-elasticsearch).
You also don't need to modify the main build.gradle file from the moqui-framework repository, dependencies should be declared in the build.gradle file in each component (which are picked up automatically in the main build).

Gradle multi-project with shared logging config

Is there a standard way to share a logging config (for log4j or logback for example) across all sub projects in a gradle project layout?
What I do right now is put a copy of logback.xml (or log4j.properties) in src/main/resources in each sub-project but this results in a lot of unnecessary duplication of this config file
This can be easily overcome using multiple working sets in gradle.
Add a new folder in the root of the project, example "shared-resources" put our configs inside it, and simple add the following line to your build.gradle on the sub-project
sourceSets {
main {
resources {
srcDirs = ["src/main/resource", "../shared-resources"]
}
}
}
This should add both files to your jar file.
An example can be find in github
Create a shared util module containing your Log4j2 configuration in its src/main/resources directory.
Then import the util module into others.
dependencies {
compile project(":util");
}
I also use the util module for re-usable Java code, not just for once-off configuration of Log4j2.

Resources