Creating Environment-specific configuration files in VS-2010 - visual-studio-2010

I'm trying to create environment specific configurations in Visual Studio 2010 and can't get the transformations to occur for anything other then the App.config. Here is an example of my scenario:
Added a configuration file in my project (e.g. Configs\Log4Net.config). The file is set to "Content" and "Copy Always"
<log4net>
<root>
<appender-ref ref="EventLogAppender" />
<level value="DEBUG" />
</root>
<appender name="EventLogAppender" type="log4net.Appender.EventLogAppender">
...
</appender>
</log4net>
Added a transformation configuration file (e.g. Configs\Log4Net.Release.config)
<log4net xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<root>
<level value="WARN" xdt:Transform="SetAttributes" xdt:Locator="XPath(log4net/root/level[#value!='WARN'])" />
</root>
</log4net>
Modified the VS Project file to include the following target
<UsingTask TaskName="TransformXml"
AssemblyFile="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll" />
<Target Name="AfterPublish" Condition="exists('Configs\Log4Net.$(Configuration).config')">
<TransformXml Source="Configs\Log4Net.config"
Destination="$(OutputPath)\Configs\Log4Net.config"
Transform="Configs\Log4Net.$(Configuration).config" />
</Target>
I've followed a similar pattern for the App.config and that works fine, but this one does not appear to work. My expectation is that when I do a Release build, the log level should be set to WARN.

I'm using XmlPreprocess tool for config files manipulation. It is using one mapping file for multiple environments. You can edit mapping file by Excel. It is very easy to use.
Try to replace your TransformXml task with Exec task and call XmlPreprocess tool.

Related

SpringBoot with LogBack creating LOG_FILE_IS_UNDEFINED folder

I am using SpringBoot with LogBack and I am trying to direct all log-statements of one specific package (here shown as "com.example.somepackagename") to a file. All other log statements should go to stdout.
At first ran into the issue that during startup a file "LOG_FILE_IS_UNDEFINED" was created. I then googled on that issue (found e.g. this on github or this on StackOverflow and a few others), but none of the appends really solved the issue.
Based on the misc. descriptions I came up with the below configuration using a logback-spring.xml-file:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<property name="LOG_PATH" value="${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}}" />
<property name="LOG_FILE" value="${LOG_FILE:-ts-msgs.log}" />
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
<include resource="org/springframework/boot/logging/logback/file-appender.xml" />
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern>
</encoder>
</appender>
<appender name="MSG_LOG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/${LOG_FILE}</file>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} : %m%n%wex</Pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>${LOG_PATH}/archived/debug.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
</appender>
<logger name="com.example.somepackagename" additivity="false" level="debug">
<appender-ref ref="MSG_LOG_FILE" />
</logger>
<logger name="org.springframework" additivity="false" level="info">
<appender-ref ref="STDOUT" />
</logger>
<root level="warn">
<appender-ref ref="STDOUT" />
</root>
</configuration>
With that I don't get a file called "LOG_FILE_IS_UNDEFINED" anymore but LogBack now always first creates an empty file "ts-msgs.log" in the working directory of the application before it creates a file with the same name in the temp-directory (where that file should go). So, somehow during initialization it already creates a file with the correct name but the correct path not being set, yet. In other words, the initialization order of Logback within SpringBoot seems broken (or at least not intuitive) and it seems impossible to avoid a first log-file being created before the correct path for the file-appender is being defined and applied.
How can one prevent that first, initial and empty log file from being created? This is necessary, since the working directory is in general write-protected and the attempt to create a file there will lead to an exception (and typically the program being terminated).
Any hints or suggestions?
BTW: I already tried to rename that file to logback.xml (which seems to be processed earlier during SpringBoot startup) but that didn't solve the issue, so I kept the suggested filename.
I get similar issue, on application start following empty file might be generated:
LOG_PATH_IS_UNDEFINED
LOG_FILE_IS_UNDEFINED
Reason
Logging related config in application.yml, is read after logback-spring.xml is parsed, thus can't read it.
Possible solutions
I found 3 possible solutions, choose one that best fit your case:
Move logging config from application.yml to bootstrap.yml, this will need spring-cloud dependency to make it work.
This works because bootstrap.yml is read before logback-spring.xml.
If you are not using spring-cloud, this probably won't be your best choice, since the extra dependencies is unnecessary.
Define path & file in logback-spring.xml directly.
e.g
<configuration>
<springProperty name="LOG_PATH" source="logging.path" defaultValue="logs/" />
<springProperty name="LOG_FILE" source="logging.file" defaultValue="app.log" />
In this case, might need to add "logback-spring.xml" to each sub project, if the log file names need to be different, and can't simply put the config file in a shared common dependency.
Just keep the config in application.yml, and ignore the generated empty files by setting .gitinore.
e.g
LOG_*_IS_UNDEFINED
In this case, the logs are still written to the file specified by application.yml, though the empty file is generate.
Tips
The logback-spring.xml file mentioned above, might be logback.xml or some other name in your case.
Removing :
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<include resource="org/springframework/boot/logging/logback/file-appender.xml"/>
from logback.xml fixed the problem for me.

How to read sql generated by NHibernate in Visual Studio

According to what I know, there are 3 ways to read the sql script generated by NHibernate:
1. log4net
2. sql profiler
3. show_sql = true
Here I just want to talk about 3rd one for it's said that I can read the sql in the output window in Visual Studio. But whatever I do, I can see nothing?!
Becasue some guy said the "show_sql = true" just means "Console.WriteLine()", so I post a question here.
I have to say I don't get what I want, so here I summarize my questions:
in the output window in an web application:
Can the result of "Console.WriteLine()" be shown?
Can "show_sql=true" make the sql script be shown?
If yes, how?
I don't think Visual Studio will show console output for a class library or website project. What I do is configure log4net to write NHibernate's SQL to a text file, then open the file in Visual Studio. With the right configuration, VS will show updates to the file by clicking in the window.
In your Web.config (or app.config), define the log4net section, have NHibernate format the SQL nicely, create a text file appender, and direct NHibernate messages there:
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="format_sql">true</property>
</session-factory>
</hibernate-configuration>
<log4net>
<appender name="NHibernateLogFile" type="log4net.Appender.FileAppender">
<file value="../Logs/NHibernate.log" />
<appendToFile value="false" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date{HH:mm:ss.fff}%m%n==========%n" />
</layout>
</appender>
<logger name="NHibernate" additivity="false">
<level value="WARN" />
<appender-ref ref="NHibernateLogFile" />
</logger>
<logger name="NHibernate.SQL" additivity="false">
<level value="DEBUG" />
<appender-ref ref="NHibernateLogFile" />
</logger>
</log4net>
</configuration>
Then open up NHibernate.Log in Visual Studio. Because of the MinimalLock above, Visual Studio can read the file at the same time log4net is writing to it. When you click in the window, VS will reload the file. Just be sure to turn this off when you deploy the web site or application.

Where does log4net write log files when debugging a web application through Visual Studio?

I'm trying to add log4net logging to a web application I'm writing. I've got this in a web service method:
log4net.Config.XmlConfigurator.Configure();
log4net.ILog log = log4net.LogManager.GetLogger(typeof(Methods));
log.Info("Some information");
And this in the web.config file:
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
</configSections>
<system.web>
<compilation debug="true" targetFramework="4.0" />
<authentication mode="Windows" />
<identity impersonate="true"/>
</system.web>
<log4net>
<appender name="LogFileAppender" type="log4net.Appender.RollFileAppender">
<file value="log.txt" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="1MB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.SimpleLayout" />
</appender>
<root>
<level value="ALL" />
<appender-ref ref="LogFileAppender" />
</root>
</log4net>
I was expecting the log file to appear in the bin\ directory when I debug it through Visual Studio 2010, but nothing is written there. The method runs successfully without any exceptions, but I can't find the log file. Any ideas as to where it should appear?
Edit - Some extra info:
According to the notification area icon, the ASP.Net Development Server is running in:
C:\Users\jpope\Documents\Visual Studio 2010\Projects\WebApplication1\WebApplication1\
The permissions on this directory and the \bin\ sub-directory both give SYSTEM, me and Administrators full control, and no one else any access. The log file is not in the directory shown above or the \bin\ sub-directory.
If you're willing to wade into some low-level stuff, it might be interesting to see what Process Monitor thinks the web server process is trying to write to. At least it would be more fun than wading through the log4net documentation.
Maybe you should set the asp.net user has the write right for you web directory.
This turned out to be a configuration problem. Switching to a FileAppender instead of a RollFileAppender works fine. Now I need to find out what's wrong with the RollFileAppender configuration...
Edit: It's a RollingFileAppender, not a RollFileAppender.

log4net console app not logging on publish

I have a console app using log4net (via Castle Windsor). Everything logs fine to the console when I debug, but when I publish and run the app, nothing is logged.
I have my log4net configuration in a separate file (log4net.config).
I'm thinking it's not finding the config file, but that's just a guess.
I'm a web dev and haven't deployed many console apps. Am I missing something?
Do I need to manually copy the log4net.config file to the exe directory?
I'm on VS2010.
app.config:
<?xml version="1.0"?>
<configuration>
<configSections>
<section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor"/>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" requirePermission="false"/>
</configSections>
<appSettings>
...
<add key="log4net.Internal.Debug" value="false"/>
</appSettings>
<startup>
<supportedRuntime version="v2.0.50727"/></startup>
<castle>
<components>
...
</components>
<facilities>
<facility id="loggingfacility" configfile="log4net.config" loggingapi="log4net" type="Castle.Facilities.Logging.LoggingFacility, Castle.Facilities.Logging"/>
</facilities>
</castle>
</configuration>
log4net.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<log4net>
<root>
<!-- Value of priority may be ALL, DEBUG, INFO, WARN, ERROR, FATAL, OFF -->
<priority value="ALL" />
<appender-ref ref="ConsoleAppender" />
</root>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%d: [%-5p] %m%n" />
</layout>
</appender>
<logger name="Castle">
<level value="INFO" />
</logger>
</log4net>
</configuration>
This is a wild guess, but have you marked "Build Action" of your log4net.config file as 'Content', and set it's property "Copy to Output directory" to "Copy always".
This way you don't have to copy file, and this file is considered as 'content' of the build output and will be included in your publish.

log4net only logs when running in the Visual Studio debugger

I'm running Visual Studio 2008 - and have a problem with log4net logging (v1.2.10).
I have a small console test program with a single log statement.
I have log4net configured for RollingLogFileAppender and ConsoleAppender.
When I run the compiled exe from the command line, I see the correct creation of the log file in my runtime directory. The log file is created (or appended to, when it exists), but the only output is the [Header] and [Footer] as configured. There is no output to console.
However, when I run under the debugger, the log message appears both in the log file and on the console. Following is my log4net configuration:
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout" value="%date [%thread] %-5level %logger - %message%newline" />
</appender>
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="quicktest-log-" />
<appendToFile value="true" />
<immediateFlush value="true" />
<datepattern value="yyyy-MM-dd" />
<maxSizeRollBackups value="100" />
<maximumFileSize value="1048576" />
<rollingStyle value="Composite" />
<staticLogFileName value="false" />
<layout type="log4net.Layout.PatternLayout">
<header value="[Begin Quicktest program log]
" />
<footer value="[End Quicktest program log]
" />
<conversionPattern value="%date{HH:mm:ss} [%thread] %-5level %logger: %message%newline" />
</layout>
</appender>
<root>
<level value="ALL" />
<appender-ref ref="ConsoleAppender" />
<appender-ref ref="RollingLogFileAppender" />
</root>
</log4net>
This theory could be a stretch, but have you ensured that the app.config has been copied to the folder where your executable is? App.config must be copied to where the output executable is, and you also must rename it to <executablename>.config, so if your executable is MyProgram.exe, config must be in MyProgram.exe.config.
It is working now, but the mystery remains. Apparently a bellyful of Chinese buffet is the only solution to a problem like this, for once I had one, the problem went away.
My test program was a single file with
class Test
{
static void Main (string[] args)
{
.
. // some logging attempted here.
.
}
}
When I had the problem originally, I was doing the logging within Main(). Afterwards, I created a method on the class Test, instantiated class Test in Main, and moved the logging to the method. This removed the problem:
class Test
{
static void Main (string[] args)
{
var p = new Test();
p.Go ();
}
public void Go ()
{
. // some logging here.
}
}
This is still inconclusive. I moved it back the way it was originally and it began working. So, I must conclude that the answer to this conundrum is: Do not attempt first-time log4net test programs without a bellyful of Chinese food.
I had the same issue, and I was doing clickonce deployment.
I found that i need to add log4net.xml in Project properties > Publish > ApplicationFiles and make this log4net.xml as datafile.

Resources