Specify directory for Serilog rolling file path - windows-services

Consider this app.config appSetting entry:
<add key="serilog:write-to:RollingFile.pathFormat"
value="ServerServiceApp-{Date}.log" />
This is done at app startup:
Log.Logger = new LoggerConfiguration()
.ReadFrom.AppSettings()
.Enrich.WithThreadId()
.CreateLogger();
This is in a Windows service app. The log file ends up here:
C:\Windows\SysWOW64
Clearly, we’d rather have the log file end up in the same directory that houses this service’s .exe (customers don’t want us writing stuff to SysWOW64). But how?
We need the ReadFrom.AppSettings in there so that the customer can supply serilog settings in the app.config, as necessary.
Is there some way to change the directory used for the log file after the ReadFrom.AppSettings has been done?
Would be awesome if we could say something like:
<add key="serilog:write-to:RollingFile.pathFormat"
value="{ApDomainBaseDirectory}\ServerServiceApp-{Date}.log" />
(And where is {Date}, which can be put in the file path, documented?)

Just put this before the creation of LoggerConfiguration:
Environment.CurrentDirectory = AppDomain.CurrentDomain.BaseDirectory;
Then File.path will be constructed based on the project root path.

The best place for services to write their logs is %PROGRAMDATA% which, by default, is in C:\ProgramData\.
Try:
<add key="serilog:write-to:RollingFile.pathFormat"
value="%PROGRAMDATA%\ServerService\Logs\log-{Date}.txt" />
(Program Files is usually considered to be read-only, and writing stuff here will lead to oddities being left behind unexpectedly during uninstall.)

Related

Using the FSharp.Configuration type provider

I'd like to the use app.config file of my F# to store versioning information. I discovered the FSharp.Configuration type provider which seemed like it'd be simple enough. However, I'm running in to an error I can't diagnose.
Below is a screen shot of a version.config file (identical to the one in the link above) and a scratch pad.
As you can see, calling Settings auto populates a drop-down of everything in the <appSettings> chunk of the config but when I try to run something,
I get an error saying that the thing I'm looking for can't be found in the <appSettings> section of the config file.
What's causing this error, especially considering that it clearly is finding it in the config file, given it's auto-populating? What can I do to prevent this from happening again?
You have bumped into this issue.
When you run the Configuration provider in FSI it will look not for the app's config file but FSI's config file. One way to get around this is by specifying the exe's config file explicitly. Here's an example:
open FSharp.Configuration
open System
type Settings = AppSettings<"app.config">
[<EntryPoint>]
let main argv =
let path = System.IO.Path.Combine [|__SOURCE_DIRECTORY__ ;"bin";"release";"ConfigApplication.exe" |]
Settings.SelectExecutableFile path
Settings.TestBool <- false // change a setting
printfn "%A" Settings.Test2 // read another setting
Console.ReadLine() |> ignore
0 // return an integer exit code
This will take the App.config file in the source directory, but use the ConfigApplication.exe.config file in the binaries directory.
If you just need to set the DB's connection string, it's actually easier, if the SQL type provider has a config setting parameter, just specify the config file there (and set it to Always copy in VS), if you add that to .gitignore you can have many different app.config files with different connection strings.
You could also use the YAML provider, it has two advantages, it's not XML and it's not an erasing type provider.

Localization with SSRS

I'm trying to localize a SSRS reports. I have a DLL that uses a ResourceManager to access resource files that are embedded in the dll. My report has a reference to the dll. The dll is signed and strongly named. The dll and resource files' dll are compiled and in MicrosoftVisualStudio9.0/Common7/IDE/PrivateAssemblies and in Microsoft SQL Server\MSRS10.REPORTSERVER\Reporting Services\ReportServer\bin. The resource dll's are also installed in the GAC using gacutil.
Occasionally the SSRS correctly finds the resource key it needs and displays it. However, when changing the resource files to add more key's and values, I cannot get the SSRS to access the newly added files. I have repeated all of the above steps and even uninstalled and installed the resources in the GAC. Still I cannot get it to work.
Any idea what step I'm missing? Clearly the process works, I'm just not repeating something that I need to be.
For those interested in a slightly different approach, you may want to try using a localization assembly that doesn't use the standard resource management, but instead relies on simple file IO. This makes making changes to existing resx files or adding new ones less problematic. You can add or change the resx files and instantly be able to retrieve values for use in the reports. I followed this example, with only minor tweaks and have been very happy with the results:
http://www.codeproject.com/Articles/294636/Localizing-SQL-Server-Reporting-Services-Reports
One note though, the steps to follow when adding the new CodeGroup are lacking a bit in that if you place the new CodeGroup anywhere except after the unnamed UnionCodeGroup (it's the one with the Url="$CodeGen$/*") your attempts to access your custom assembly will fail.
After a lot of digging I was able to find confirmation of this on one of the msdn pages (see the "Placement of CodeGroup Elements for Extensions" section). Their wording was that "it is recommended", but from my testing I'd say it's required, at least when testing directly on the report server:
http://msdn.microsoft.com/en-us/library/ms152828.aspx
The xpath to use in wix for this location in the rssrvpolicy.config file is:
//PolicyLevel/CodeGroup/CodeGroup[\[]#class='FirstMatchCodeGroup'[\]]/CodeGroup[\[]#PermissionSetName='ReportLocalization'[\]]
Here's an example of how this can be done in WiX using the util:XmlConfig extension:
<DirectoryRef Id="TARGETDIR">
<Component Id="I18N_RSSRVPOLICY_CONFIG" Guid="some GUID">
<util:XmlConfig
Id="RS_i18n_PermissionSet_remove_if_already_exists"
File="[SQLREPORTINGSERVICESPATH]ReportServer\rssrvpolicy.config"
Action="delete"
On="install"
ElementPath="//NamedPermissionSets"
VerifyPath="//NamedPermissionSets/PermissionSet[\[]#Name='ReportLocalization'[\]]"
Node="element"
Sequence="100">
</util:XmlConfig>
<util:XmlConfig
Id="RS_i18n_PermissionSet_add"
File="[SQLREPORTINGSERVICESPATH]ReportServer\rssrvpolicy.config"
Action="create"
On="install"
ElementPath="//NamedPermissionSets"
VerifyPath="//NamedPermissionSets/PermissionSet[\[]#Name='ReportLocalization'[\]]"
Node="document"
Sequence="101">
<![CDATA[
<PermissionSet class="NamedPermissionSet" version="1" Unrestricted="true" Name="ReportLocalization" Description="A special permission set that allows Execution and Assertion" />
]]>
</util:XmlConfig>
<util:XmlConfig
Id="RS_i18n_CodeGroup_remove_if_already_exists"
File="[SQLREPORTINGSERVICESPATH]ReportServer\rssrvpolicy.config"
Action="delete"
On="install"
ElementPath="//PolicyLevel/CodeGroup/CodeGroup[\[]#class='FirstMatchCodeGroup'[\]]"
VerifyPath="//PolicyLevel/CodeGroup/CodeGroup[\[]#class='FirstMatchCodeGroup'[\]]/CodeGroup[\[]#PermissionSetName='ReportLocalization'[\]]"
Node="element"
Sequence="102">
</util:XmlConfig>
<util:XmlConfig
Id="RS_i18n_CodeGroup_add"
File="[SQLREPORTINGSERVICESPATH]ReportServer\rssrvpolicy.config"
Action="create"
On="install"
ElementPath="//PolicyLevel/CodeGroup/CodeGroup[\[]#class='FirstMatchCodeGroup'[\]]"
VerifyPath="//PolicyLevel/CodeGroup/CodeGroup[\[]#class='FirstMatchCodeGroup'[\]]/CodeGroup[\[]#PermissionSetName='ReportLocalization'[\]]"
Node="document"
Sequence="103">
<![CDATA[
<CodeGroup class="UnionCodeGroup" version="1" PermissionSetName="ReportLocalization" Name="Verint.SSRS.Localization" Description="This grants the Verint.SSRS.Localization.dll ReportLocalization Permissions">
<IMembershipCondition class="UrlMembershipCondition" version="1" Url="UPDATE_ME"/>
</CodeGroup>]]>
</util:XmlConfig>
<util:XmlConfig
Id="RS_i18n_CodeGroup_update"
File="[SQLREPORTINGSERVICESPATH]ReportServer\rssrvpolicy.config"
Action="create"
On="install"
ElementPath="//IMembershipCondition[\[]#Url='UPDATE_ME'[\]]"
Name="Url"
Value="[SQLREPORTINGSERVICESPATH]ReportServer\bin\Verint.SSRS.Localization.dll"
Node="value"
Sequence="104">
</util:XmlConfig>
<util:XmlConfig
Id="RS_i18n_REDP_CodeGroup_update"
File="[SQLREPORTINGSERVICESPATH]ReportServer\rssrvpolicy.config"
Action="create"
On="install"
ElementPath="//CodeGroup[\[]#Name='Report_Expressions_Default_Permissions'[\]]"
Name="PermissionSetName"
Value="FullTrust"
Node="value"
Sequence="105">
</util:XmlConfig>
</Component>
</DirectoryRef>
I recommend backing up the original config files (with WiX or custom actions). This can make uninstall easier since you can just replace those originals, and also because you can test this over and over again till it's doing what you want. Good luck to you all!
Are your rebuilding and redeploying all the satellite assemblies with each of your updates (including in the GAC)?
If not, it sounds like the problem is due to assembly versioning. There is a SatelliteContractVersion attribute that you can apply to your main assembly to help with this problem. Although rebuilding/resigning/redeploying all satellite assemblies each time you deploy an update may be easier.

MvcRoutingShim plugin has no effect

I'm using the ImageResizer module in an ASP.NET MVC 4 project, along with the plugins SqlReader and MvcRoutingShim.
When I try to access the URL ~/databaseimages/123.jpg (for example), I just get the standard error 404 - The resource cannot be found.
My expectation was that ImageResizer would handle that request and try to read the image from the database, but it doesn't even try to connect (I used SQL Profiler to verify this).
What can be wrong?
This is the output of /resizer.debug:
Image resizer diagnostic sheet 26-06-2012 20:42:57
1 Issues detected:
(Warning): To potentially see additional errors here, perform an image resize request.
You are using paid bundles: Cloud Bundle, Performance Bundle
Registered plugins:
ImageResizer.Plugins.Basic.DefaultEncoder
ImageResizer.Plugins.Basic.NoCache
ImageResizer.Plugins.Basic.ClientCache
ImageResizer.Plugins.Basic.Diagnostic
ImageResizer.Plugins.Basic.SizeLimiting
ImageResizer.Plugins.MvcRoutingShim.MvcRoutingShimPlugin
ImageResizer.Plugins.SqlReader.SqlReaderPlugin
ImageResizer.Plugins.DiskCache.DiskCache
Configuration:
<resizer>
<plugins>
<add name="MvcRoutingShim" />
<add name="SqlReader" prefix="~/databaseimages/" connectionString="database" idType="UniqueIdentifier" blobQuery="SELECT Content FROM Images WHERE ImageID=#id" modifiedQuery="Select ModifiedDate, CreatedDate From Images WHERE ImageID=#id" existsQuery="Select COUNT(ImageID) From Images WHERE ImageID=#id" requireImageExtension="false" cacheUnmodifiedFiles="true" extensionPartOfId="false" vpp="true" untrustedData="false" />
<add name="DiskCache" />
</plugins>
</resizer>
(...)
In your Web.config file, you declared that image IDs are all GUIDs: idType="UniqueIdentifier", yet used a integer in the url: localhost:50272/databaseimages/123.jpg.
<add name="SqlReader" prefix="~/databaseimages/" connectionString="database"
idType="UniqueIdentifier" requireImageExtension="false"
cacheUnmodifiedFiles="true" extensionPartOfId="false"
vpp="true" untrustedData="false" />
If you're not specifying a GUID in the URL, the request will be ignored. Change idType to a different data type, like Int, or use the correct data type in the URL.
Source: http://imageresizing.net/plugins/sqlreader

Is it possible to have a dynamic resource path for import?

I have a Spring.NET program with a configuration file. To smooth the transition from test to prod I'd like to have an environment variable that gives the path to a shared config file, and use that to import a resource, however it appears the <import resource="path"/> is not being resolved. For example if I try to load the file <import resource="\\server\share\${computername}\SpringConfig.xml"/> I get a file not found exception as below:
System.Configuration.ConfigurationErrorsException: Error creating context 'spring.root': file [\server\share\${computername}\SpringConfig.xml] cannot be resolved to local file path - resource does not use 'file:' protocol. ---> Spring.Objects.Factory.ObjectDefinitionStoreException: IOException parsing XML document from file [\server\share\${computername}\SpringConfig.xml] ---> System.IO.FileNotFoundException: file [\server\share\${computername}\SpringConfig.xml] cannot be resolved to local file path - resource does not use 'file:' protocol.
Is there a way I can have a dynamic import path in Spring.NET, preferably without writing code?
You can do that anyway with some extra code:
Create your own FileSystemResource that will replace placeholders in the resource name. Start from overriding the existing FileSystemResource (In Spring.Core.IO namespace)
Register your new IResource implementation in the container using your own protocol name (ex: myfile://) See ref docs here for an example :
In .NET configuration file (app.config/web.config)
http://www.springframework.net/doc-latest/reference/html/resources.html#d4e2911
In Spring configuration files
http://www.springframework.net/doc-latest/reference/html/objects.html#context-custom-resourcehandler
Use it!
resource="myfile://\server\share\${computername}\SpringConfig.xml"
I don't think we can do that with the current version.
Latest Java version supports it, so we can expect this feature in a future version (Using variables environnement by default)

NLog File splitting

I'm using NLog to log to file. Is there a way to configure it to create a new log file when the current one reaches a certain threshold (eg ~50mb)? Can it be done from the configuration file or code?
Yes:
fileName="${basedir}/logs/logfile.txt"
archiveFileName="${basedir}/archives/log.{#####}.txt"
archiveAboveSize="5242880"
archiveNumbering="Sequence"
concurrentWrites="true" <!-- http://nlog-project.org/doc/2.0/sl2/html/P_NLog_Targets_FileTarget_ArchiveAboveSize.htm -->

Resources