Empty Default String for Property in logback.xml - spring-boot

Our project structure regarding the logback.xmls looks like this:
src\main\resources\logback.xml
src\main\resources\config\dev\logback.xml
src\main\resources\config\sjngm\dev\logback.xml
src\main\resources\config\int\logback.xml
src\main\resources\config\local\logback.xml
src\main\resources\config\prod\logback.xml
where the first one references to the environment specific one:
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="30 seconds">
<contextName>sjngm</contextName>
<jmxConfigurator />
<include resource="config/${extra}${env:-local}/logback.xml" />
</configuration>
Note that extra is not defined most of the times, which is why used this for a while:
<include resource="config/${extra:-}${env:-local}/logback.xml" />
This stopped working at one point, can't remember which version of logback. So we changed it to
<include resource="config/${extra:-./}${env:-local}/logback.xml" />
which also worked for quite a while.
Now we switched to Spring Boot 1.5.4 (contains logback-classic 1.1.11 and logback-core 1.1.11) and it stopped working again. The latest error message is:
11:08:15,020 |-WARN in ch.qos.logback.core.joran.action.IncludeAction - Could not find resource corresponding to [config/./local/logback.xml]
If I go back to
<include resource="config/${extra:-}${env:-local}/logback.xml" />
the message is
11:19:28,778 |-WARN in ch.qos.logback.core.joran.action.IncludeAction - Could not find resource corresponding to [config/extra_IS_UNDEFINEDlocal/logback.xml]
Note that logback still uses "local" as a default string for env, so not all is broken.
What do I do now? Basically I want to tell logback that I want an empty string where extra would be.

This also doesn't work:
<property name="defaultExtra" value="" />
<include resource="config/${extra:-${defaultExtra}}${env:-local}/logback.xml" />
as an empty string seems to always result in an undefined property.
The only working thing I can come up with is this:
<if condition='isDefined("extra")'>
<then>
<include resource="config/${extra}${env:-local}/logback.xml" />
</then>
<else>
<include resource="config/${env:-local}/logback.xml" />
</else>
</if>
plus this into the pom.xml:
<dependency>
<groupId>org.codehaus.janino</groupId>
<artifactId>janino</artifactId>
</dependency>
Isn't this nice?! So why did they have to break what was working nicely???

This worked for me:
<property name="extra" value="${logback.myApp.extra:- }" />
Logback seems to trim Whitespace out of the value. So the default value of Space did the trick.
Embedded Whitespace is preserved, which may lead to a FileNotFoundException if Tabs were embedded, but embedded Spaces were ok.
Setting a Property in a Java Initialiser had the desired effect:
System.setProperty("logback.myApp.extra", "\t \tEXTRA_EXTRA_EXTRA\t \t");
The Tabs & Spaces were removed from the Property, which was assigned the value EXTRA_EXTRA_EXTRA
(the Java Initialiser must be invoked before any Logging has taken place & may contain no Logging itself)
You could of course set the Property on the Java Command line.
P.S. if the Property is undefined & you omit the Space (${logback.myApp.extra:-}), it is assigned the value:
logback.myApp.extra_IS_UNDEFINED
...so it may be wise to add a suitable comment:
<property name="extra" value="${logback.myApp.extra:- }" /><!-- N.B. Empty Default value must contain # least 1 Space!! -->

Related

How to put resource value of property tag in backlog into application.properties

I have logback-spring.xml that contains my configuration and I have another file log.properties that I put values that I am using in logback-spring.xml in it and added to my logback-spring.xml by using <property resource= /> tag.
what I need is to retrieve the value for this property tag from application.properties, right now I directly use the address <property resource="config/properties/log.properties" />
following is the structure of files:
-- src/main/resources
----- config
-------- logging
----------- logback-spring.xml
-------- properties
----------- log.properties
-------- application.properties
As I read other questions I tried some of them but they didn't work, I tried the following solutions:
I added log.properties=classpath:config/properties/log.properties to application.properties and then added <property resource="${log.properties}" /> tag to logback-spring.xml but it didn't work.
then I tried these two tags together
<property resource="application.properties" />
<property resource="${log.properties}" />
unfortunately still no chance, I am wondering if it is possible at all or not, if I can't retrieve a valuer for <property/> tag from application.properties then how I can externalize this hard-coded value?
I found that the problem was with addresses so I changed the value in my logback-spring.xml and application.properties as follow:
log.properties
<property resource="config/application.properties" />
application.properties
log.properties=config/properties/log.properties
It is now working fine but still, I am not sure it is a good practice to have two <property> tags in logback-spring.xml or there is a better way to do this?

How to set max number of archived logs in spring boot

I tried following settings in application.properties:
logging.file=foo/bar.log
logging.file.max-history=2
logging.file.max-size=1KB
Still, its not limiting the number of archive logs to 2.
As per application properties documentation reference, only supported when you setup logback.
logging.file.max-history=0 # Maximum of archive log files to keep. Only supported with the default logback setup.
So to add support of logback please see section 79.1 Configure Logback for Logging & 79.1.1 Configure Logback for File-only Output of Spring Boot Logging Guide
If you want to disable console logging and write output only to a
file, you need a custom logback-spring.xml that imports
file-appender.xml but not console-appender.xml, as shown in the
following example:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
<property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}spring.log}"/>
<include resource="org/springframework/boot/logging/logback/file-appender.xml" />
<root level="INFO">
<appender-ref ref="FILE" />
</root>
</configuration>

Can you explain this Spring environment variable resolution?

The Spring Boot docs have the following sample logging file:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
<property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}spring.log}"/>
<include resource="org/springframework/boot/logging/logback/file-appender.xml" />
<root level="INFO">
<appender-ref ref="FILE" />
</root>
</configuration>
Can you help me understand the line ${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}spring.log}? What are the - for?
Like Bash, Logback uses :- as its default value operator. The line in question is setting the LOG_FILE property:
If LOG_FILE is already set, use that
Otherwise, if LOG_PATH is set, use that suffixed with spring.log
Otherwise, if LOG_TEMP is set, use that suffixed with /spring.log
Otherwise, if java.io.tmpdir is set, use that suffixed with /spring.log
Otherwise use /tmp/spring.log
It has nothing to do with Spring.
Logback XML configuration itself has such kind of placeholder handling to replace the placeholders with variable. The syntax for placeholder in logback is ${VARNAME}, and if you want default value if VARNAME is not present, you can do it by ${VARNAME:-DEFAULT} (ref: Logback Configuration). Yes, a :-, follow by the default value.
Then what you quote is easy to understand:
${LOG_FILE:- }
${LOG_PATH:- }spring.log
${LOG_TEMP:- }/
${java.io.tmpdir:- }
/tmp
(Do you actually need explanation on what the above means?)

TeamCity REST API: Triggering Build with Custom Artifact Dependency

I'm trying to trigger a custom build using the TeamCity 8.1 REST API (see https://confluence.jetbrains.com/display/TCD8/REST+API#RESTAPI-TriggeringaBuild). My builds run fine and I'm able to specify custom branches and properties with no issue. My goal is now to specify a custom artifact dependency for the builds I'm triggering.
The response I receive when creating a build is something like the following:
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<build taskId="1234" buildTypeId="buildConfig1" state="queued" ...>
<buildType id="buildConfig1" name="Build Config Name" ... />
...
<properties count="1">
<property name="testParam" value="Test 123" own="true" />
</properties>
<custom-artifact-dependencies />
</build>
The "custom-artifact-dependencies" tag in this response leads me to believe that there is a way to specify custom dependencies, but I have not found anything in the TeamCity documentation, the TeamCity forums, or from Google explaining how this can be accomplished. Is there something I'm overlooking here or another way of accomplishing this?
Adding the following to as a child of the "build" tag results in an "Artifact dependency should have type 'artifact_dependency'." error:
<custom-artifact-dependencies>
<artifact-dependency buildId="5432" buildTypeId="parentBuildConfig"/>
</custom-artifact-dependencies>
The server may be confusing my intention with the build configuration API for setting and viewing artifact dependencies (e.g. http://teamcity:8111/httpAuth/app/rest/buildTypes/<buildTypeLocator>/artifact-dependencies/)
I had the same problem
This is what worked for me:
<build>
<triggeringOptions queueAtTop="true"/>
<buildType id="buildConfig1"/>
<custom-artifact-dependencies count="1">
<artifact-dependency id="0" type="artifact_dependency">
<properties>
<property name="pathRules" value="Artifacts_1.zip
Artifacts_2.zip
Artifacts_To_Unzip.zip!/**
"/>
<property name="cleanDestinationDirectory" value="true"/>
<property name="revisionName" value="buildId"/>
<property name="revisionValue" value="5432"/>
</properties>
<source-buildType id="parentBuildConfig" />
</artifact-dependency>
</custom-artifact-dependencies>
</build>
If the 'parentBuildConfig' build is still running, replace the buildId parameter with taskId

mybatis spring mvc application, getting Invalid bound statement (not found)

this is my first mybatis spring mvc application using spring 3.2.4, mybatis-spring-1.2.1
When i try to call my webservice i get the error::
org.springframework.web.util.NestedServletException: Request processing failed;
nested exception is org.apache.ibatis.binding.BindingException: Invalid bound
statement (not found):
org.mydomain.formulary.drugmaster.dao.DrugMasterDao.getDrugsWithAlert
I must be missing something obvious.
Thanks for any help
Here are my associated files:
applicationContext.xml
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="formularyDb" />
<property name="configLocation" value="file:/web/sites/drugformulary-spring/config/mybatis-config.xml" />
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="org.mydomain.formulary.mappers" />
</bean>
<bean id="DrugMasterDao" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="org.mydomain.formulary.drugmaster.dao.DrugMasterDao" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory" />
</bean>
mapper file --> /classes/org/mydomain/formulary/mappers/drugmasterDao.xml
<mapper namespace="org.mydomain.formulary.drugmaster.dao.DrugMasterDao">
<select id="getDrugsWithAlert" parameterType="int" resultType="org.mydomain.formulary.drug_master.model.DrugMasters">
Select drug_id,drug_name,drug_alert_date,drug_alert_source, rownum
from (select drug_id,drug_name,to_char(drug_alert_datetime,'MM/DD/YYYY') as drug_alert_date ,drug_alert_source, rownum
from drug_master
where drug_status ='A' and length(drug_alert) > 0
order by drug_alert_datetime DESC )
where
<if test="_parameter != null">
rownum < #{count}
</if>
</select>
</mapper>
mapper file --> /classes/org/mydomain/formulary/drugmaster/dao/DrugMasterDao.java
public interface DrugMasterDao {
public List<DrugMasters> getDrugsWithAlert(int count);
}
controller file --> /classes/org/mydomain/formulary/drugmaster/controller/DrugMasterController.java
#Controller
public class DrugMasterController {
#Autowired
DrugMasterService drugMasterService;
#RequestMapping(value = "/drugmaster/withalerts/count/{count}", method = RequestMethod.GET)
public String withAlerts(ModelMap model, #PathVariable int count) {
List<DrugMasters> drugs = drugMasterService.getDrugsWithAlert(count);
return null/*for now*/;
}
}
service file --> /classes/org/mydomain/formulary/drugmaster/service/DrugMasterServiceImpl.java
#Service
public class DrugMasterServiceImpl implements DrugMasterService {
#Autowired
DrugMasterDao drugMasterDao;
public List<DrugMasters> getDrugsWithAlert(int count){
return drugMasterDao.getDrugsWithAlert(count);
}
}
mybatis-configfile -->
<configuration>
<settings>
<setting name="cacheEnabled" value="false" />
<setting name="lazyLoadingEnabled" value="false" />
</settings>
</configuration>
I googled this answer when looking for my error. It's actually unrelated to OP's problem, but the exception is the same and this question's very visible in google.
In my case I forgot to change the mapper namespace
<mapper namespace="pl.my.package.MyNewMapper">
Which resulted in the same problem.
I had the same problem so after reading the configurations in this page.
https://mybatis.github.io/spring/mappers.html#scan
I saw that my configuration was correct. so debugging my application. found that my *mappers.xml files where not in the path. that expect must be.
I had the XML files in the same folder src "java" in my maven project. so when I build my applications the file were not copy to classes folder. So I have to move the xml files to folder "resources". and the fix the problem.
Because your xml not load in mybatis, MapperScannerConfigurer only scan interface, not xml.
Have two way:
<mappers>
<mapper resource="org/mydomain/formulary/mappers/drugmasterDao.xml"/>
</mappers>
or
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="dataSource" ref="dataSource"/>
<property name="mapperLocations" value="classpath*:org/mydomain/**/*.xml"/>
</bean>
i had similar problem for my spring-boot mybatis application.
The issue was mybatis couldn't find the configuration file. After adding
mybatis.config-location=classpath:mybatis-config.xml
in the application.properties file, issue got resolved. Looks like issue is always around configuration files/mapper files and statement names.
In my case, I had multiple DataSource and should set mappler locations for each SessionFactory.
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(mysqlDataSource);
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
sessionFactory.setMapperLocations(resolver.getResources("classpath:mappers/**/*Mapper.xml"));
(There could be many reasons, my case is a bit rare & weird, it's hard to discover, so I'd like to add an answer here, just in case someone did the same thing as me.)
In my case, then reason is in IDEA, when create multi-level package for mapper file I input mybatis.mapper, which only create a single dir but with name contains ..
While I should actually input mybatis/mapper to create multi-level dir at once.
In these 2 cases, the dir are shown the same as mybatis.mapper in the project view of IDEA, so it took me quiet a while to figure out why ...
I resolved the same problem with a variant of the solution of Giovanni Perea(thank you). I have the .xml mapper files in the same folder with .java mapper files and I using maven with maven-resources-plugin.
In my solution I have add an execution in maven-resources-plugin for copy all the .xml mapper file to the correct location(same folder of the .class mapper files):
<execution>
<id>copy-mappers-xml</id>
<phase>validate</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/classes/com/myapplication/mapper</outputDirectory>
<resources>
<resource>
<directory>${project.basedir}/src/main/java/com/myapplication/mapper/</directory>
<filtering>false</filtering>
<includes>
<include>*.xml</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
More examples with maven-resources-plugin: Including and excluding files and directories
If you do not use maven-resources-plugin see:
https://stackoverflow.com/a/12446666/2473158
In my case it was a typo error in the id of the mapper xml statement e.g.
<select id="getDtaa" resultType="Data">
List<T> getData()
After changing the id in the XML to the correct function name it worked.
most likely the java method name and the XML block's name mismatches
e.g mapper.getUser()
<select id="getUsee" resultMap="student">
...........
<>
getUser obviously different from getUsee
Except for #Dariusz mentioned above, I've also forgotten to add mapper location.
<property name="mapperLocations" value="classpath:mybatis/mappers/*.xml"/>
in the spring configuration, taking a xml way for example, make sure that the mapper.xml files are located at the place assigned as the value of the property named mapperLocations. Once I had it at mappers/anotherfolder/*.xml. And that causes the pain.
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="typeAliasesPackage" value="somepackage.model"/>
<property name="mapperLocations" value="classpath*:mappers/*.xml"/>
</bean>
Rename mapper/drugmasterDao.xml to mapper/DrugMasterDao.xml , the name has to match the *Dao.java file name otherwise it throws error
or
we have to create Ibatismapping.xml explictly and add mapper configuration there
Check if there is any overload method in mapper. Try to use a separate name instead.
I have also encountered this problem in my development.
In generall, if you are using xml configuration files for spring,myBatis and etc., then this problem is mostly caused by some mistake in your xml configuration files.
The most voted answer by Dariusz demonstrated that there maybe some problems in the myBatis xml configuration file, while in my case, I found that problems in spring xml configuration file can also result in this problem.
In the situation of this post, in the applicationContext.xml(which should be a configuration file of Spring), we can see a basePackage configuration for the MapperScannerConfigurer:
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="org.mydomain.formulary.mappers" />
</bean>
so if the value for this property is wrong(the package name is not right), it will also result in this problem.
2 Points to cover
Check whether the method name is the same in both the XML and Java methods.
Mapper:scan covers the required package. If you are using annotation then #MapperScan(com.xxx) must be in the defined path.
In my case, using a query in an annotation, i didn't give enough credit to the fact that the XML in the annotation gets interpreted as XML.
So if you have
#Select("select * from table where id <> 'blabla'")
The <> is messing up the XML. You need to put it in a CDATA section
#Select("select * from table where id <![CDATA[ <> ]]> 'blabla'")
I think the issue is that MyBatis can't find the XML mapper configuration file. In my project using Spring Boot with MyBatis-3, I configured the mapper location in the application.properties as shown below:
mybatis.mapper-locations=classpath:mappers/*.xml
If you're using application.yml instead of .properties:
mybatis:
mapper-locations: "classpath:mappers/*.xml"
DrugMasters attributes defines must associate with the drug_id,drug_name,drug_alert_date,drug_alert_source, rownum .

Resources