I am using Serilog and want to print some information message that contains contextual property.
For example:
var logger = Log.ForContext("FirstName", "Yosi");
logger.Information("Hello {FirstName}")
and this works as expected, but when I add parameter to the log message it self, I get unexpected result.
var logger = Log.ForContext("FirstName", "Yosi");
logger.Information("Hello {FirstName} {LastName}", "Attias")
I expect the result to be:
Hello Yosi Attias
but I get:
Hello Attias {LastName}
Is there a fix for that? am I missing something? or this is a bug?
Message templates are only evaluated against the parameters that are passed in to the logging method. Log statements are intended to work consistently regardless of any other configuration/context in the program.
If you want to add additional properties to the logging output, add them to the outputTemplate argument of whatever sink you are configuring:
Log.Logger = new LoggerConfiguration()
.WriteTo.ColoredConsole(outputTemplate:
"{Timestamp:HH:mm} [{Level}] ({LastName}) {Message}{NewLine}{Exception}")
.CreateLogger();
use refection to add properties and their values automatically to log them all in Serilog:
public static Task GenericLog(MyClassLog myclassLog, string message=null)
{
if (string.IsNullOrEmpty(message)) message = nameof(myclassLog);
var properties = typeof(MyClassLog).GetProperties();
var propertyEnrichers = new PropertyEnricher[properties.Length];
for (int i = 0; i < properties.Length; i++)
propertyEnrichers[i] =
new PropertyEnricher(
properties[i].Name,
properties[i].GetValue(myclassLog)
);
var withProps = Log.ForContext(propertyEnrichers);
withProps.Debug(message);
return Task.CompletedTask;
}
Related
We have a customised TFS workflow, I want to be able to access the Reasons I can close a Bug (change the state from Active to Closed) from TFS so that we don't have to update our code every time we want to tweak our process.
This is what I have so far:
WorkItemType wiType = this.GetWorkItemStore().Projects[this.ProjectName].WorkItemTypes["Bug"];
var reason = wiType.FieldDefinitions["Reason"];
var state = wiType.FieldDefinitions["State"];
var filterList = new FieldFilterList();
FieldFilter filter = new FieldFilter(wiType.FieldDefinitions[CoreField.State], "Active");
filterList.Add(filter);
var allowedReasons = reason.FilteredAllowedValues(filterList);
However I'm not getting any results. I'd like to get a list of all the reasons why I can close a bug (Not Reproduceable, Fixed etc)
There isn't any easy way to get the transition via API directly as I know since the API read the allowed values from database directly.
The alternative way would be export the workitemtype definition via WorkItemType.Export() method and then get the information from it. Vaccano's answer in this question provided the entire code sample you can use.
Edited to give an example of how I solved this using the above recommendation:
public static List<Transition> GetTransistions(this WorkItemType workItemType)
{
List<Transition> currentTransistions;
// See if this WorkItemType has already had it's transistions figured out.
_allTransistions.TryGetValue(workItemType, out currentTransistions);
if (currentTransistions != null)
return currentTransistions;
// Get this worktype type as xml
XmlDocument workItemTypeXml = workItemType.Export(false);
// Create a dictionary to allow us to look up the "to" state using a "from" state.
var newTransistions = new List<Transition>();
// get the transistions node.
XmlNodeList transitionsList = workItemTypeXml.GetElementsByTagName("TRANSITIONS");
// As there is only one transistions item we can just get the first
XmlNode transitions = transitionsList[0];
// Iterate all the transitions
foreach (XmlNode transition in transitions)
{
XmlElement defaultReasonNode = transition["REASONS"]["DEFAULTREASON"];
var defaultReason = defaultReasonNode.Attributes["value"].Value;
var otherReasons = new List<string>();
XmlNodeList otherReasonsNodes = transition["REASONS"].SelectNodes("REASON");
foreach (XmlNode reasonNode in otherReasonsNodes)
{
var reason = reasonNode.Attributes["value"].Value;
otherReasons.Add(reason);
}
// save off the transistion
newTransistions.Add(new Transition
{
From = transition.Attributes["from"].Value,
To = transition.Attributes["to"].Value,
DefaultReason = defaultReason,
OtherReasons = otherReasons
});
}
// Save off this transition so we don't do it again if it is needed.
_allTransistions.Add(workItemType, newTransistions);
return newTransistions;
}
I'm using jericho's SourceFormatter to do indentation of HTML.
Right now if there is an issue in my HTML formatter sends it to server console.
How can I catch error and output it into my log system (actually I want to get it as a String/Object)?
Here is example of code I use
private String indent(String html) {
SourceFormatter formatter = new SourceFormatter(new Source(html));
formatter.setIndentString("\t");
formatter.setTidyTags(false);
formatter.setCollapseWhiteSpace(true);
return formatter.toString(); // if HTML have issues, they go to server's consol
}
LoggerProvider - represent loggin system of hericho
I found that it is possible to realize Logger interface and use it as your own logger.
class LoggerCustom implements net.htmlparser.jericho.Logger {
...
}
And than pass it's object to Source object.
Source source = new Source(html);
LoggerCustom logger = new LoggerCustom();
source.setLogger(logger); // here I pass my Logger object.
SourceFormatter formatter = new SourceFormatter(source);
formatter.setIndentString("\t");
formatter.setTidyTags(false);
formatter.setCollapseWhiteSpace(true);
String result = formatter.toString();
I want to generate a report that contains data from a database using a filter stored in a ViewData.
My question is how I will pass the ViewData value of the report as a parameter to display some data.
Controller :
var Soc = (string)TempData["Societe"];
XtraReport report = new Training.UI.Web.Reporting.Etat1();
report.DataSource = from p in db.TEntreprises
where p.EntNom == Soc
select p;
report.Parameters.Add(new DevExpress.XtraReports.Parameters.Parameter() { Name = "EntNom", Type = typeof(String), Value = Soc, Description = "NomEntreprise" });
ViewData["Report"] = report;
return PartialView("DocumentViewerPartial");
View :
#Html.DevExpress().DocumentViewer(settings =>
{
settings.Name = "documentViewer1";
settings.StylesSplitter.SidePaneWidth = 340;
settings.Report = (Training.UI.Web.Reporting.Etat1) ViewData["Report"];
settings.CallbackRouteValues = new { Controller = "Etat1", Action = "DocumentViewerPartial" };
settings.ExportRouteValues = new { Controller = "Etat1", Action = "ExportDocumentViewer" };
}).GetHtml()
And I have no data in the XtraReport
To apply the values to the report, create a string that contains the report name and the submitted values, and pass this string to the viewer’s OpenReport method.
The example below demonstrates how to do the following:
Create a page with a document viewer and button.
Create a string with the report name and a predefined parameter value and pass this string to the viewer’s OpenReport method on a button click.
Viewer.cshtml
<script type="text/javascript">
function OnClick() {
var reportName = "XtraReport1";
var paramName = "strParam";
var paramValue = "42";
var reportUrl = reportName + '?' + paramName + '=' + paramValue;
WebDocumentViewer1.OpenReport(reportUrl);
}
</script>
#Html.DevExpress().Button(settings => {
settings.Name = "dxOpenButton";
settings.Text = "Submit parameter";
settings.ClientSideEvents.Click = "OnClick";
}).GetHtml()
#Html.DevExpress().WebDocumentViewer(settings => {
settings.Name = "WebDocumentViewer1";
}).Bind("XtraReport1").GetHtml()
When you call the viewer’s OpenReport method, the reporting engine executes a report name resolution service. This service creates a report instance and returns it to the viewer. Implement this service to apply the parameter values to the report. The string argument from the OpenReport method is passed to the service’s method that returns a report instance. In this method, do the following:
Parse the string argument to extract the report name and parameter values.
Create a report instance and apply the parameter values to it. Reference each parameter by name in the report’s Parameters collection and assign the value to the parameter’s Value property.
If you want custom UI elements to be the only way to submit parameter values, hide the Parameters Panel. To do this, disable the Visible property for all report parameters. If you want users to submit parameter values from both the panel and custom UI elements, disable the report’s RequestParameters property.
Return the report instance.
When you create a Web Reporting application from the DevExpress Template Gallery, you can add the Report Storage service to the application. This service will be utilized as a report name resolution service in your application. For this, implement the service’s GetData method as follows:
CustomReportStorageWebExtenstion.CS
public override byte[] GetData(string url) {
try {
// Parse the string with the report name and parameter values.
string[] parts = url.Split('?');
string reportName = parts[0];
string parametersQueryString = parts.Length > 1 ? parts[1] : String.Empty;
// Create a report instance.
XtraReport report = null;
if (Directory.EnumerateFiles(reportDirectory).
Select(Path.GetFileNameWithoutExtension).Contains(reportName)) {
byte[] reportBytes = File.ReadAllBytes(Path.Combine(reportDirectory, reportName + FileExtension));
using (MemoryStream ms = new MemoryStream(reportBytes))
report = XtraReport.FromStream(ms);
}
if (report != null) {
// Apply the parameter values to the report.
var parameters = HttpUtility.ParseQueryString(parametersQueryString);
foreach (string parameterName in parameters.AllKeys) {
report.Parameters[parameterName].Value = Convert.ChangeType(
parameters.Get(parameterName), report.Parameters[parameterName].Type);
}
// Disable the Visible property for all report parameters
// to hide the Parameters Panel in the viewer.
foreach (var parameter in report.Parameters) {
parameter.Visible = false;
}
// If you do not hide the panel, disable the report's RequestParameters property.
// report.RequestParameters = false;
using (MemoryStream ms = new MemoryStream()) {
report.SaveLayoutToXml(ms);
return ms.ToArray();
}
}
} catch (Exception) {
// ...
}
To apply parameter values from a URL query string to a report, implement the viewer’s action method as follows:
Create a report instance and apply the parameter values to it. Reference each parameter by name in the report’s Parameters collection and assign the value to the parameter’s Value property.
If you want a URL’s query string to be the only way to submit parameter values, hide the Parameters Panel. To do this, disable the Visible property for all report parameters. If you want users to submit parameter values from both the panel and a URL’s query string, disable the report’s RequestParameters property.
Return a report view.
The example below demonstrates how to implement the viewer’s action method to apply the parameter value from the query string of the following URL: https://localhost:5001/Home/Viewer?intParam=42.
HomeController.cs
public ActionResult Viewer(int? intParam) {
var report = new XtraReport1();
report.Parameters["intParam"].Value = intParam;
report.Parameters["intParam"].Visible = false;
return View(report);
}
enter image description here
I am trying to subscribe to CheckinEvent in TFS 2010 using TFS IEventService. For some reason I keep getting:
Event type <<event type>> does not exist
for WorkItemChangedEvent and CheckinEvent. What am I doing wrong?
var serverUri = new Uri("http://TFS_SERVICE:8080/tfs");
var server = TfsConfigurationServerFactory.GetConfigurationServer(serverUri);
var eventService = server.GetService<IEventService>();
var preference = new DeliveryPreference
{
Schedule = DeliverySchedule.Immediate,
Type = DeliveryType.Soap,
Address = "http://localhost:61773/NotifyService.asmx"
};
int eventId = eventService.SubscribeEvent("CheckinEvent", null, preference);
You are querying the Event Service at the Configuration Server level. These event types only exist at the team project collection level, which I assume is where you actually want to create your event subscription. You would need to change your code to something like the following:
var serverUri = new Uri("http://TFS_SERVICE:8080/tfs/collection");
TfsTeamProjectCollection collection = new TfsTeamProjectCollection(serverUri);
var eventService = collection.GetService<IEventService>();
var preference = new DeliveryPreference
{
Schedule = DeliverySchedule.Immediate,
Type = DeliveryType.Soap,
Address = "http://localhost:61773/NotifyService.asmx"
};
int eventId = eventService.SubscribeEvent("CheckinEvent", null, preference);
Please note that the URI needs to include your collection name.
Instead of using the TfsConfigurationServerFactory, use the TfsTeamProjectCollectionFactory.GetTeamProjectCollection() method. These events exist at the collection level, rather than the server level.
var config = Db4oEmbedded.NewConfiguration ();
using (var container = Db4oEmbedded.OpenFile (config, FILE))
{
var foo = new Foo ("Test");
container.Store (foo);
foo.Name = "NewName";
container.Store (foo);
}
Any way to resolve the history of container for foo in the format below?
Foo created with values "Test" Foo
Foo's property "Test" changed to "NewName"
You can do by implementing event-handlers. Basically you can register a event-handler for the creating and the updating event. Like this:
IEventRegistry events = EventRegistryFactory.ForObjectContainer(container);
events.Creating +=delegate(object sender, CancellableObjectEventArgs args)
{
Console.WriteLine("{0} created: Value {1}",args.Object.GetType(),args.Object);
};
For viewing value changes you maybe need to peek the old state in the event-handler. You can do this like this:
IEventRegistry events = EventRegistryFactory.ForObjectContainer(container);
events.Creating +=delegate(object sender, CancellableObjectEventArgs args)
{
IObjectContainer eventContainer = args.ObjectContainer();
object oldVersion = eventContainer.Ext().Peek(args.Object,1,false);
object currentVersion = args.Object;
// Do comparison and print stuff
};
Of course the comparison and printing is the work you have to do. There's nothing built in for that.