How do I programmatically report the TFS/AzureDevOps changeset number in my logsLog4Net, how to add a custom field to my loggingI ran into a merge conflict. How can I abort the merge?How to undo 'git add' before commit?How to change the author and committer name and e-mail of multiple commits in Git?How to list branches that contain a given commit?How do I generate a random int number?How can I view a git log of just one user's commits?How can I delete all Git branches which have been merged?Does anyone have benchmarks (code & results) comparing performance of Android apps written in Xamarin C# and Java?How to see the changes in a Git commit?Using IPython notebooks under version control
Can I cause damage to electrical appliances by unplugging them when they are turned on?
What is the smallest number n> 5 so that 5 ^ n ends with "3125"?
What does "tick" mean in this sentence?
Alignment of six matrices
Sigmoid with a slope but no asymptotes?
If the only attacker is removed from combat, is a creature still counted as having attacked this turn?
How to leave product feedback on macOS?
Can you identify this lizard-like creature I observed in the UK?
Personal or impersonal in a technical resume
In One Punch Man, is King actually weak?
Would this string work as string?
SOQL query causes internal Salesforce error
Why is the Sun approximated as a black body at ~ 5800 K?
Is there a reason to prefer HFS+ over APFS for disk images in High Sierra and/or Mojave?
Sound waves in different octaves
Possible Eco thriller, man invents a device to remove rain from glass
How much do grades matter for a future academia position?
Ways of geometrical multiplication
I'm just a whisper. Who am I?
Did I make a mistake by ccing email to boss to others?
Is there a RAID 0 Equivalent for RAM?
Air travel with refrigerated insulin
Identifying "long and narrow" polygons in with PostGIS
How to make a list of partial sums using forEach
How do I programmatically report the TFS/AzureDevOps changeset number in my logs
Log4Net, how to add a custom field to my loggingI ran into a merge conflict. How can I abort the merge?How to undo 'git add' before commit?How to change the author and committer name and e-mail of multiple commits in Git?How to list branches that contain a given commit?How do I generate a random int number?How can I view a git log of just one user's commits?How can I delete all Git branches which have been merged?Does anyone have benchmarks (code & results) comparing performance of Android apps written in Xamarin C# and Java?How to see the changes in a Git commit?Using IPython notebooks under version control
I sometimes find myself binary searching through changesets and running tests to determine when a defect was introduced. This leaves me with a lot of very similar logs to sift through, and sometimes I have trouble remembering which diagnostic file came from which changeset run.
I would like to include the changeset number in the diagnostic files somehow. Is there any way to do this with Visual Studio/C#/AzureDevOps?
c# tfs version-control azure-devops system-testing
add a comment |
I sometimes find myself binary searching through changesets and running tests to determine when a defect was introduced. This leaves me with a lot of very similar logs to sift through, and sometimes I have trouble remembering which diagnostic file came from which changeset run.
I would like to include the changeset number in the diagnostic files somehow. Is there any way to do this with Visual Studio/C#/AzureDevOps?
c# tfs version-control azure-devops system-testing
What logging framework are you using? I might be able to provide a framework-specific example.
– xander
Mar 8 at 0:26
log4net plus some adhoc csv files
– ORcoder
Mar 8 at 16:22
Here's a related answer that gives an example of adding custom fields to log4net output: stackoverflow.com/questions/12139486/…
– xander
Mar 8 at 17:25
add a comment |
I sometimes find myself binary searching through changesets and running tests to determine when a defect was introduced. This leaves me with a lot of very similar logs to sift through, and sometimes I have trouble remembering which diagnostic file came from which changeset run.
I would like to include the changeset number in the diagnostic files somehow. Is there any way to do this with Visual Studio/C#/AzureDevOps?
c# tfs version-control azure-devops system-testing
I sometimes find myself binary searching through changesets and running tests to determine when a defect was introduced. This leaves me with a lot of very similar logs to sift through, and sometimes I have trouble remembering which diagnostic file came from which changeset run.
I would like to include the changeset number in the diagnostic files somehow. Is there any way to do this with Visual Studio/C#/AzureDevOps?
c# tfs version-control azure-devops system-testing
c# tfs version-control azure-devops system-testing
asked Mar 7 at 21:52
ORcoderORcoder
1144
1144
What logging framework are you using? I might be able to provide a framework-specific example.
– xander
Mar 8 at 0:26
log4net plus some adhoc csv files
– ORcoder
Mar 8 at 16:22
Here's a related answer that gives an example of adding custom fields to log4net output: stackoverflow.com/questions/12139486/…
– xander
Mar 8 at 17:25
add a comment |
What logging framework are you using? I might be able to provide a framework-specific example.
– xander
Mar 8 at 0:26
log4net plus some adhoc csv files
– ORcoder
Mar 8 at 16:22
Here's a related answer that gives an example of adding custom fields to log4net output: stackoverflow.com/questions/12139486/…
– xander
Mar 8 at 17:25
What logging framework are you using? I might be able to provide a framework-specific example.
– xander
Mar 8 at 0:26
What logging framework are you using? I might be able to provide a framework-specific example.
– xander
Mar 8 at 0:26
log4net plus some adhoc csv files
– ORcoder
Mar 8 at 16:22
log4net plus some adhoc csv files
– ORcoder
Mar 8 at 16:22
Here's a related answer that gives an example of adding custom fields to log4net output: stackoverflow.com/questions/12139486/…
– xander
Mar 8 at 17:25
Here's a related answer that gives an example of adding custom fields to log4net output: stackoverflow.com/questions/12139486/…
– xander
Mar 8 at 17:25
add a comment |
1 Answer
1
active
oldest
votes
Microsoft used to support a file called BuildInfo.config
that was useful for this exact sort of thing, but I think support for it was dropped after Visual Studio 2015.
Basically, it was a simple XML file that was created by MSBuild. When deployed alongside the app binaries, a logging framework could read the file and include the details in log output.
There are a bunch of ways you might create similar functionality yourself. Here's what I'd do...
- Create an empty build info file and check it in with your source code. This file is just a reference example--use placeholder data. It can be XML, JSON, or any other format (but should probably be text-based). Set the file's build action to "Content," so it will be included in the build output.
- Use your logging framework's template or telemetry initialization functionality to read the build info file and include its contents in log output. The exact implementation will depend on your logging framework.
- Add a Powershell script task to your Azure DevOps pipeline. The script should either update or overwrite the build info file. You can get some good info from build variables. The task should run before the MSBuild compilation step.
Create and Parse a BuildInfo file
For this example, I'm going to implement my build info file as simple key/value
pairs in a text file. I chose simple text because it allows a clear example
without requiring any third-party libraries or complex parsing. In your app, you
might want to use JSON, XML, or something else more standardized.
First, create a placeholder build info file. This file will be used in your
local dev environment, and will serve as a reference for your build info schema.
I called mine BuildInfo.txt
, and put it in my project's root directory.
COMMIT=commit not set
BUILD=build not set
Next, write a helper to parse the build info file. Mine's very rudimentary. It
would be wise to add some defenses against missing or malformed build info, but
I chose to omit any defensive code to keep the example focused.
class BuildInfo
// Singleton instance backing field
static readonly Lazy<BuildInfo> instance = new Lazy<BuildInfo>(() => new BuildInfo());
// Singleton instance public accessor
public static BuildInfo Instance => instance.Value;
public string Commit get;
public string Build get;
private BuildInfo()
// This is a very rudimentary example of parsing the info file. It
// will fail loudly on malformed input. Consider:
// 1) Using a standard file format (JSON, XML). I rolled my own
// here to avoid adding a dependency on a parsing library.
// 2) If you want your app to fail when no build info is
// available, add a more descriptive exception. If you don't
// want it to fail, add some devensive code or fallback logic.
var info = File.ReadAllLines("BuildInfo.txt")
.Select(l => l.Split('=', 2))
.ToDictionary(key => key[0], val => val[1]);
Commit = info["COMMIT"];
Build = info["BUILD"];
Add the Build Info to your Log Output
I'm using log4net here, but any logging framework should have some similar
mechanism to customise the log output. Consult the framework's documentation for
more info.
First, add your build info to the logging context. This should go somewhere in
your app's startup code--as early as possible.
log4net.GlobalContext.Properties["Build"] = BuildInfo.Instance.Build;
log4net.GlobalContext.Properties["Commit"] = BuildInfo.Instance.Commit;
Then, update your log appender's configuration to include the custom fields.
Here's an example configuration for the the console appender. The important bits
are %propertyBuildId
and %propertyCommit
.
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<target value="Console.Error" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-5level [%propertyBuildId] [%propertyCommit] - %message%newline" />
</layout>
</appender>
<root>
<level value="ALL"/>
<appender-ref ref="ConsoleAppender" />
</root>
</log4net>
Now, when you call log.Warn("Some log mesage")
, you'll see the following
console output:
WARN [build not set] [commit not set] - Some log mesage
Get Build Details from CI
Finally, you need to get the real build details from your CI environment. I did
this with a very simple PowerShell script task. Make sure the task runs before
your build step!
@(
"COMMIT=$($Env:BUILD_SOURCEVERSION)",
"BUILD=$($Env:BUILD_BUILDID)"
) | Out-File BuildInfo.txt
(Tip: You can see all of the environment variables available by running Get-ChildItem Env: | Sort Name
in a PowerShell task)
(Another tip: if you want to use JSON instead of text, take a look at the ConvertTo-Json
cmdlet)
Now, if all of the pieces are in place, the CI server should overwrite the
checked-in build info file. The new file should then be packages with your
deployable artifacts, and copied to your server. On startup, your app should
read the build info, and then the info should be included in every log message.
There are a lot of little things to get lined up between your build and deploy
process, so be prepared for some trial and error. CI/CD setup tends to be
tedious, in my experience.
I assume the you are saying that the build info file holds the changeset number and the Powershell script task overwrites it with the correct changeset. How does the powershell script know which changeset we are on?
– ORcoder
Mar 8 at 19:58
1
Take a look at the "build variables" link. The variables expose lots of good information--the changeset (Build.SourceVersion
), the branch (Build.SourceBranchName
), even the commit message (Build.SourceVersionMessage
). I'll add some example code as soon as I have time to write/test it.
– xander
Mar 8 at 20:09
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55053393%2fhow-do-i-programmatically-report-the-tfs-azuredevops-changeset-number-in-my-logs%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
Microsoft used to support a file called BuildInfo.config
that was useful for this exact sort of thing, but I think support for it was dropped after Visual Studio 2015.
Basically, it was a simple XML file that was created by MSBuild. When deployed alongside the app binaries, a logging framework could read the file and include the details in log output.
There are a bunch of ways you might create similar functionality yourself. Here's what I'd do...
- Create an empty build info file and check it in with your source code. This file is just a reference example--use placeholder data. It can be XML, JSON, or any other format (but should probably be text-based). Set the file's build action to "Content," so it will be included in the build output.
- Use your logging framework's template or telemetry initialization functionality to read the build info file and include its contents in log output. The exact implementation will depend on your logging framework.
- Add a Powershell script task to your Azure DevOps pipeline. The script should either update or overwrite the build info file. You can get some good info from build variables. The task should run before the MSBuild compilation step.
Create and Parse a BuildInfo file
For this example, I'm going to implement my build info file as simple key/value
pairs in a text file. I chose simple text because it allows a clear example
without requiring any third-party libraries or complex parsing. In your app, you
might want to use JSON, XML, or something else more standardized.
First, create a placeholder build info file. This file will be used in your
local dev environment, and will serve as a reference for your build info schema.
I called mine BuildInfo.txt
, and put it in my project's root directory.
COMMIT=commit not set
BUILD=build not set
Next, write a helper to parse the build info file. Mine's very rudimentary. It
would be wise to add some defenses against missing or malformed build info, but
I chose to omit any defensive code to keep the example focused.
class BuildInfo
// Singleton instance backing field
static readonly Lazy<BuildInfo> instance = new Lazy<BuildInfo>(() => new BuildInfo());
// Singleton instance public accessor
public static BuildInfo Instance => instance.Value;
public string Commit get;
public string Build get;
private BuildInfo()
// This is a very rudimentary example of parsing the info file. It
// will fail loudly on malformed input. Consider:
// 1) Using a standard file format (JSON, XML). I rolled my own
// here to avoid adding a dependency on a parsing library.
// 2) If you want your app to fail when no build info is
// available, add a more descriptive exception. If you don't
// want it to fail, add some devensive code or fallback logic.
var info = File.ReadAllLines("BuildInfo.txt")
.Select(l => l.Split('=', 2))
.ToDictionary(key => key[0], val => val[1]);
Commit = info["COMMIT"];
Build = info["BUILD"];
Add the Build Info to your Log Output
I'm using log4net here, but any logging framework should have some similar
mechanism to customise the log output. Consult the framework's documentation for
more info.
First, add your build info to the logging context. This should go somewhere in
your app's startup code--as early as possible.
log4net.GlobalContext.Properties["Build"] = BuildInfo.Instance.Build;
log4net.GlobalContext.Properties["Commit"] = BuildInfo.Instance.Commit;
Then, update your log appender's configuration to include the custom fields.
Here's an example configuration for the the console appender. The important bits
are %propertyBuildId
and %propertyCommit
.
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<target value="Console.Error" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-5level [%propertyBuildId] [%propertyCommit] - %message%newline" />
</layout>
</appender>
<root>
<level value="ALL"/>
<appender-ref ref="ConsoleAppender" />
</root>
</log4net>
Now, when you call log.Warn("Some log mesage")
, you'll see the following
console output:
WARN [build not set] [commit not set] - Some log mesage
Get Build Details from CI
Finally, you need to get the real build details from your CI environment. I did
this with a very simple PowerShell script task. Make sure the task runs before
your build step!
@(
"COMMIT=$($Env:BUILD_SOURCEVERSION)",
"BUILD=$($Env:BUILD_BUILDID)"
) | Out-File BuildInfo.txt
(Tip: You can see all of the environment variables available by running Get-ChildItem Env: | Sort Name
in a PowerShell task)
(Another tip: if you want to use JSON instead of text, take a look at the ConvertTo-Json
cmdlet)
Now, if all of the pieces are in place, the CI server should overwrite the
checked-in build info file. The new file should then be packages with your
deployable artifacts, and copied to your server. On startup, your app should
read the build info, and then the info should be included in every log message.
There are a lot of little things to get lined up between your build and deploy
process, so be prepared for some trial and error. CI/CD setup tends to be
tedious, in my experience.
I assume the you are saying that the build info file holds the changeset number and the Powershell script task overwrites it with the correct changeset. How does the powershell script know which changeset we are on?
– ORcoder
Mar 8 at 19:58
1
Take a look at the "build variables" link. The variables expose lots of good information--the changeset (Build.SourceVersion
), the branch (Build.SourceBranchName
), even the commit message (Build.SourceVersionMessage
). I'll add some example code as soon as I have time to write/test it.
– xander
Mar 8 at 20:09
add a comment |
Microsoft used to support a file called BuildInfo.config
that was useful for this exact sort of thing, but I think support for it was dropped after Visual Studio 2015.
Basically, it was a simple XML file that was created by MSBuild. When deployed alongside the app binaries, a logging framework could read the file and include the details in log output.
There are a bunch of ways you might create similar functionality yourself. Here's what I'd do...
- Create an empty build info file and check it in with your source code. This file is just a reference example--use placeholder data. It can be XML, JSON, or any other format (but should probably be text-based). Set the file's build action to "Content," so it will be included in the build output.
- Use your logging framework's template or telemetry initialization functionality to read the build info file and include its contents in log output. The exact implementation will depend on your logging framework.
- Add a Powershell script task to your Azure DevOps pipeline. The script should either update or overwrite the build info file. You can get some good info from build variables. The task should run before the MSBuild compilation step.
Create and Parse a BuildInfo file
For this example, I'm going to implement my build info file as simple key/value
pairs in a text file. I chose simple text because it allows a clear example
without requiring any third-party libraries or complex parsing. In your app, you
might want to use JSON, XML, or something else more standardized.
First, create a placeholder build info file. This file will be used in your
local dev environment, and will serve as a reference for your build info schema.
I called mine BuildInfo.txt
, and put it in my project's root directory.
COMMIT=commit not set
BUILD=build not set
Next, write a helper to parse the build info file. Mine's very rudimentary. It
would be wise to add some defenses against missing or malformed build info, but
I chose to omit any defensive code to keep the example focused.
class BuildInfo
// Singleton instance backing field
static readonly Lazy<BuildInfo> instance = new Lazy<BuildInfo>(() => new BuildInfo());
// Singleton instance public accessor
public static BuildInfo Instance => instance.Value;
public string Commit get;
public string Build get;
private BuildInfo()
// This is a very rudimentary example of parsing the info file. It
// will fail loudly on malformed input. Consider:
// 1) Using a standard file format (JSON, XML). I rolled my own
// here to avoid adding a dependency on a parsing library.
// 2) If you want your app to fail when no build info is
// available, add a more descriptive exception. If you don't
// want it to fail, add some devensive code or fallback logic.
var info = File.ReadAllLines("BuildInfo.txt")
.Select(l => l.Split('=', 2))
.ToDictionary(key => key[0], val => val[1]);
Commit = info["COMMIT"];
Build = info["BUILD"];
Add the Build Info to your Log Output
I'm using log4net here, but any logging framework should have some similar
mechanism to customise the log output. Consult the framework's documentation for
more info.
First, add your build info to the logging context. This should go somewhere in
your app's startup code--as early as possible.
log4net.GlobalContext.Properties["Build"] = BuildInfo.Instance.Build;
log4net.GlobalContext.Properties["Commit"] = BuildInfo.Instance.Commit;
Then, update your log appender's configuration to include the custom fields.
Here's an example configuration for the the console appender. The important bits
are %propertyBuildId
and %propertyCommit
.
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<target value="Console.Error" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-5level [%propertyBuildId] [%propertyCommit] - %message%newline" />
</layout>
</appender>
<root>
<level value="ALL"/>
<appender-ref ref="ConsoleAppender" />
</root>
</log4net>
Now, when you call log.Warn("Some log mesage")
, you'll see the following
console output:
WARN [build not set] [commit not set] - Some log mesage
Get Build Details from CI
Finally, you need to get the real build details from your CI environment. I did
this with a very simple PowerShell script task. Make sure the task runs before
your build step!
@(
"COMMIT=$($Env:BUILD_SOURCEVERSION)",
"BUILD=$($Env:BUILD_BUILDID)"
) | Out-File BuildInfo.txt
(Tip: You can see all of the environment variables available by running Get-ChildItem Env: | Sort Name
in a PowerShell task)
(Another tip: if you want to use JSON instead of text, take a look at the ConvertTo-Json
cmdlet)
Now, if all of the pieces are in place, the CI server should overwrite the
checked-in build info file. The new file should then be packages with your
deployable artifacts, and copied to your server. On startup, your app should
read the build info, and then the info should be included in every log message.
There are a lot of little things to get lined up between your build and deploy
process, so be prepared for some trial and error. CI/CD setup tends to be
tedious, in my experience.
I assume the you are saying that the build info file holds the changeset number and the Powershell script task overwrites it with the correct changeset. How does the powershell script know which changeset we are on?
– ORcoder
Mar 8 at 19:58
1
Take a look at the "build variables" link. The variables expose lots of good information--the changeset (Build.SourceVersion
), the branch (Build.SourceBranchName
), even the commit message (Build.SourceVersionMessage
). I'll add some example code as soon as I have time to write/test it.
– xander
Mar 8 at 20:09
add a comment |
Microsoft used to support a file called BuildInfo.config
that was useful for this exact sort of thing, but I think support for it was dropped after Visual Studio 2015.
Basically, it was a simple XML file that was created by MSBuild. When deployed alongside the app binaries, a logging framework could read the file and include the details in log output.
There are a bunch of ways you might create similar functionality yourself. Here's what I'd do...
- Create an empty build info file and check it in with your source code. This file is just a reference example--use placeholder data. It can be XML, JSON, or any other format (but should probably be text-based). Set the file's build action to "Content," so it will be included in the build output.
- Use your logging framework's template or telemetry initialization functionality to read the build info file and include its contents in log output. The exact implementation will depend on your logging framework.
- Add a Powershell script task to your Azure DevOps pipeline. The script should either update or overwrite the build info file. You can get some good info from build variables. The task should run before the MSBuild compilation step.
Create and Parse a BuildInfo file
For this example, I'm going to implement my build info file as simple key/value
pairs in a text file. I chose simple text because it allows a clear example
without requiring any third-party libraries or complex parsing. In your app, you
might want to use JSON, XML, or something else more standardized.
First, create a placeholder build info file. This file will be used in your
local dev environment, and will serve as a reference for your build info schema.
I called mine BuildInfo.txt
, and put it in my project's root directory.
COMMIT=commit not set
BUILD=build not set
Next, write a helper to parse the build info file. Mine's very rudimentary. It
would be wise to add some defenses against missing or malformed build info, but
I chose to omit any defensive code to keep the example focused.
class BuildInfo
// Singleton instance backing field
static readonly Lazy<BuildInfo> instance = new Lazy<BuildInfo>(() => new BuildInfo());
// Singleton instance public accessor
public static BuildInfo Instance => instance.Value;
public string Commit get;
public string Build get;
private BuildInfo()
// This is a very rudimentary example of parsing the info file. It
// will fail loudly on malformed input. Consider:
// 1) Using a standard file format (JSON, XML). I rolled my own
// here to avoid adding a dependency on a parsing library.
// 2) If you want your app to fail when no build info is
// available, add a more descriptive exception. If you don't
// want it to fail, add some devensive code or fallback logic.
var info = File.ReadAllLines("BuildInfo.txt")
.Select(l => l.Split('=', 2))
.ToDictionary(key => key[0], val => val[1]);
Commit = info["COMMIT"];
Build = info["BUILD"];
Add the Build Info to your Log Output
I'm using log4net here, but any logging framework should have some similar
mechanism to customise the log output. Consult the framework's documentation for
more info.
First, add your build info to the logging context. This should go somewhere in
your app's startup code--as early as possible.
log4net.GlobalContext.Properties["Build"] = BuildInfo.Instance.Build;
log4net.GlobalContext.Properties["Commit"] = BuildInfo.Instance.Commit;
Then, update your log appender's configuration to include the custom fields.
Here's an example configuration for the the console appender. The important bits
are %propertyBuildId
and %propertyCommit
.
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<target value="Console.Error" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-5level [%propertyBuildId] [%propertyCommit] - %message%newline" />
</layout>
</appender>
<root>
<level value="ALL"/>
<appender-ref ref="ConsoleAppender" />
</root>
</log4net>
Now, when you call log.Warn("Some log mesage")
, you'll see the following
console output:
WARN [build not set] [commit not set] - Some log mesage
Get Build Details from CI
Finally, you need to get the real build details from your CI environment. I did
this with a very simple PowerShell script task. Make sure the task runs before
your build step!
@(
"COMMIT=$($Env:BUILD_SOURCEVERSION)",
"BUILD=$($Env:BUILD_BUILDID)"
) | Out-File BuildInfo.txt
(Tip: You can see all of the environment variables available by running Get-ChildItem Env: | Sort Name
in a PowerShell task)
(Another tip: if you want to use JSON instead of text, take a look at the ConvertTo-Json
cmdlet)
Now, if all of the pieces are in place, the CI server should overwrite the
checked-in build info file. The new file should then be packages with your
deployable artifacts, and copied to your server. On startup, your app should
read the build info, and then the info should be included in every log message.
There are a lot of little things to get lined up between your build and deploy
process, so be prepared for some trial and error. CI/CD setup tends to be
tedious, in my experience.
Microsoft used to support a file called BuildInfo.config
that was useful for this exact sort of thing, but I think support for it was dropped after Visual Studio 2015.
Basically, it was a simple XML file that was created by MSBuild. When deployed alongside the app binaries, a logging framework could read the file and include the details in log output.
There are a bunch of ways you might create similar functionality yourself. Here's what I'd do...
- Create an empty build info file and check it in with your source code. This file is just a reference example--use placeholder data. It can be XML, JSON, or any other format (but should probably be text-based). Set the file's build action to "Content," so it will be included in the build output.
- Use your logging framework's template or telemetry initialization functionality to read the build info file and include its contents in log output. The exact implementation will depend on your logging framework.
- Add a Powershell script task to your Azure DevOps pipeline. The script should either update or overwrite the build info file. You can get some good info from build variables. The task should run before the MSBuild compilation step.
Create and Parse a BuildInfo file
For this example, I'm going to implement my build info file as simple key/value
pairs in a text file. I chose simple text because it allows a clear example
without requiring any third-party libraries or complex parsing. In your app, you
might want to use JSON, XML, or something else more standardized.
First, create a placeholder build info file. This file will be used in your
local dev environment, and will serve as a reference for your build info schema.
I called mine BuildInfo.txt
, and put it in my project's root directory.
COMMIT=commit not set
BUILD=build not set
Next, write a helper to parse the build info file. Mine's very rudimentary. It
would be wise to add some defenses against missing or malformed build info, but
I chose to omit any defensive code to keep the example focused.
class BuildInfo
// Singleton instance backing field
static readonly Lazy<BuildInfo> instance = new Lazy<BuildInfo>(() => new BuildInfo());
// Singleton instance public accessor
public static BuildInfo Instance => instance.Value;
public string Commit get;
public string Build get;
private BuildInfo()
// This is a very rudimentary example of parsing the info file. It
// will fail loudly on malformed input. Consider:
// 1) Using a standard file format (JSON, XML). I rolled my own
// here to avoid adding a dependency on a parsing library.
// 2) If you want your app to fail when no build info is
// available, add a more descriptive exception. If you don't
// want it to fail, add some devensive code or fallback logic.
var info = File.ReadAllLines("BuildInfo.txt")
.Select(l => l.Split('=', 2))
.ToDictionary(key => key[0], val => val[1]);
Commit = info["COMMIT"];
Build = info["BUILD"];
Add the Build Info to your Log Output
I'm using log4net here, but any logging framework should have some similar
mechanism to customise the log output. Consult the framework's documentation for
more info.
First, add your build info to the logging context. This should go somewhere in
your app's startup code--as early as possible.
log4net.GlobalContext.Properties["Build"] = BuildInfo.Instance.Build;
log4net.GlobalContext.Properties["Commit"] = BuildInfo.Instance.Commit;
Then, update your log appender's configuration to include the custom fields.
Here's an example configuration for the the console appender. The important bits
are %propertyBuildId
and %propertyCommit
.
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<target value="Console.Error" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-5level [%propertyBuildId] [%propertyCommit] - %message%newline" />
</layout>
</appender>
<root>
<level value="ALL"/>
<appender-ref ref="ConsoleAppender" />
</root>
</log4net>
Now, when you call log.Warn("Some log mesage")
, you'll see the following
console output:
WARN [build not set] [commit not set] - Some log mesage
Get Build Details from CI
Finally, you need to get the real build details from your CI environment. I did
this with a very simple PowerShell script task. Make sure the task runs before
your build step!
@(
"COMMIT=$($Env:BUILD_SOURCEVERSION)",
"BUILD=$($Env:BUILD_BUILDID)"
) | Out-File BuildInfo.txt
(Tip: You can see all of the environment variables available by running Get-ChildItem Env: | Sort Name
in a PowerShell task)
(Another tip: if you want to use JSON instead of text, take a look at the ConvertTo-Json
cmdlet)
Now, if all of the pieces are in place, the CI server should overwrite the
checked-in build info file. The new file should then be packages with your
deployable artifacts, and copied to your server. On startup, your app should
read the build info, and then the info should be included in every log message.
There are a lot of little things to get lined up between your build and deploy
process, so be prepared for some trial and error. CI/CD setup tends to be
tedious, in my experience.
edited Mar 10 at 0:41
answered Mar 8 at 0:23
xanderxander
632516
632516
I assume the you are saying that the build info file holds the changeset number and the Powershell script task overwrites it with the correct changeset. How does the powershell script know which changeset we are on?
– ORcoder
Mar 8 at 19:58
1
Take a look at the "build variables" link. The variables expose lots of good information--the changeset (Build.SourceVersion
), the branch (Build.SourceBranchName
), even the commit message (Build.SourceVersionMessage
). I'll add some example code as soon as I have time to write/test it.
– xander
Mar 8 at 20:09
add a comment |
I assume the you are saying that the build info file holds the changeset number and the Powershell script task overwrites it with the correct changeset. How does the powershell script know which changeset we are on?
– ORcoder
Mar 8 at 19:58
1
Take a look at the "build variables" link. The variables expose lots of good information--the changeset (Build.SourceVersion
), the branch (Build.SourceBranchName
), even the commit message (Build.SourceVersionMessage
). I'll add some example code as soon as I have time to write/test it.
– xander
Mar 8 at 20:09
I assume the you are saying that the build info file holds the changeset number and the Powershell script task overwrites it with the correct changeset. How does the powershell script know which changeset we are on?
– ORcoder
Mar 8 at 19:58
I assume the you are saying that the build info file holds the changeset number and the Powershell script task overwrites it with the correct changeset. How does the powershell script know which changeset we are on?
– ORcoder
Mar 8 at 19:58
1
1
Take a look at the "build variables" link. The variables expose lots of good information--the changeset (
Build.SourceVersion
), the branch (Build.SourceBranchName
), even the commit message (Build.SourceVersionMessage
). I'll add some example code as soon as I have time to write/test it.– xander
Mar 8 at 20:09
Take a look at the "build variables" link. The variables expose lots of good information--the changeset (
Build.SourceVersion
), the branch (Build.SourceBranchName
), even the commit message (Build.SourceVersionMessage
). I'll add some example code as soon as I have time to write/test it.– xander
Mar 8 at 20:09
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55053393%2fhow-do-i-programmatically-report-the-tfs-azuredevops-changeset-number-in-my-logs%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
What logging framework are you using? I might be able to provide a framework-specific example.
– xander
Mar 8 at 0:26
log4net plus some adhoc csv files
– ORcoder
Mar 8 at 16:22
Here's a related answer that gives an example of adding custom fields to log4net output: stackoverflow.com/questions/12139486/…
– xander
Mar 8 at 17:25