C# EventViewer Logs Parsing - c#

I am in charge of parsing forwarded EventViewer (evt) logs (Windows 7?). To do this I am run a query using Log Parser 2.2 over the logs and pulling out specific EventIDs and writing these to a CSV file. However, I am considering using EventViewerReader to do this instead.
The query I am doing on these evt includes a "strings" column which outputs a bunch of junk usually of the format: SID|Username|Usergroup|... but it isn't consistent. What I want is a consistent way to get the username for these events and filter out the useless data. The problem is that I don't understand the format for the output. I am wondering if these events have a standard format or if this is a custom format from my work? The method I have right now basically looks for known usergroups and checks for potential usernames to the left of them (skipping "LOCALS SERVICE", "NETWORK SERVICE", "-", and some other keywords). My issue with this method is that I don't know all of the usergroups, and I can get false-positives on usernames.
Here are some of the EventID Codes I am looking at:
https://www.ultimatewindowssecurity.com/securitylog/quickref/downloads/quickref.zip
4624 An account was successfully logged on
4625 An account failed to log on
4647 User initiated logoff
4648 A logon was attempted using explicit credentials
4800 The workstation was locked
4801 The workstation was unlocked
4802 The screen saver was invoked
4803 The screen saver was dismissed

I ended up looking closer at the evt files and saw they have a set XML schema. "Strings" isn't really an element, but a the concatonated values of EventData child Data elements. All I did was look at the schema for each EventID and found the depth of the username in each event type.
I think it was strings[5] (TargetUserName) for logon/logoff, strings[0] for a couple others, and strings[1] for a couple more.
<EventData>
<Data Name="SubjectUserSid">S-1-5-18</Data>
<Data Name="SubjectUserName">XXX-PC$</Data>
<Data Name="SubjectDomainName">WORKGROUP</Data>
<Data Name="SubjectLogonId">0x3e7</Data>
<Data Name="TargetUserSid">S-1-5-18</Data>
<Data Name="TargetUserName">SYSTEM</Data>
<Data Name="TargetDomainName">NT AUTHORITY</Data>
<Data Name="TargetLogonId">0x3e7</Data>
...
</EventData>

Related

Logging multiple threads with nlog

I use nlog logger in my project.
My program generates xml files based on data which i getting from sql server. I'm doing this with PLINQ. But also i have to log tracing info to be able make some investigations on exceptional cases on prod environment.
Result logs looks awful, when it came from multiple threads. For example:
Operation 1 started
Deserializing XXX
Operation 2 started
Deserializing XXX finished with status X
Filling XXX with data from Z
Deserializing YYY....
And its just for degree of parallelism 2.
I'd like to see result like this:
Operation 1 started
Deserializing XXX
Deserializing XXX finished with status X
Filling XXX with data from Z
Operation 1 finished
Operation 2 started
Deserializing YYY....
I see some solutions, but they're not looking good enough:
Save logging data to some buffer and flush it when parallel task ends - I will be ought to pass context to all inner methods (looks terrible!).
Add some kind of prefix to logging message to help getting context for some messages - i have to pass prefix to every inner message (also looks terrible).
Is there some clean solutions for this problem?
In NLog config files, there is the ${threadid} syntax. Use it like this:
<target name="file" xsi:type="File"
layout="${longdate} [${threadid}] ${level:uppercase=true} ${message} ${exception:format=tostring}"
fileName="${basedir}/logs/log.txt"
archiveFileName="${basedir}/logs/log.{#####}.txt"
archiveAboveSize="10485760"
archiveNumbering="Sequence"
concurrentWrites="true"
keepFileOpen="false" />
More info:
https://github.com/NLog/NLog/wiki/ThreadId-Layout-Renderer
I used it in production and generally it works. It is not perfect, but all operations (which I logged) is in sequence and this threadid describe which operation is in which ThreadId.

DNN Localization of an IActionable Menu Item Returns Null

I am going absolutely nuts and hope someone can help me find what I'm overlooking. I've got a user control that implements IActionable and no matter what I try, I cannot get the Localized text on the menu items to return anything other than null! I've used the common resources, "AddAction.Action", etc with no luck. I've tried explicitly stating which resource to use and that's not working either. These is the last two items that need localization on this whole module and I just can't get it to cooperate. They navigate properly, just won't display the text.
On the User Control Testimonial.ascx.cs:
//add the Manage Testimonials action button
var Actions = new ModuleActionCollection();
Actions.Add(GetNextActionID(),
Localization.GetString(ModuleActionType.EditContent, this.LocalResourceFile),
ModuleActionType.EditContent,
"",
"",
EditUrl(),
false,
DotNetNuke.Security.SecurityAccessLevel.Edit,
true,
false);
Actions.Add(GetNextActionID(),
Localization.GetString("AddContent.Action", LocalResourceFile,
ModuleActionType.AddContent,
"",
"",
EditUrl("AddTestimonial"),
false,
DotNetNuke.Security.SecurityAccessLevel.Edit,
true,
false);
return Actions;
On the App_LocalResources\Testimonial.ascx.resx:
<data name="AddContent.Action" xml:space="preserve">
<value>Add New Testimonial Localized</value>
</data>
<data name="AddContent.Text" xml:space="preserve">
<value>Add Content Text</value>
</data>
<data name="EditContent.Action" xml:space="preserve">
<value>Manage Testimonials Localized</value>
</data>
I've tried every combination of things I can possibly think of, but it shouldn't be anything more than the call to the Localization.GetString method. I've NEVER had an issue like this before and I'm about to throw my head through the window. ANY help or pointers are sincerely appreciated!!
Thanks!
I ran into this same problem as well. After finding this document and then reading down on page 15 http://www.dotnetnuke.nl/Portals/16/downloads/documenten/DotNetNuke%20Module%20Localization%20Guide.pdf
Basically some crazy magic happens where DNN appends ".Text" to whatever the end of a resource key is.
so...
what you'll need to do as a resource string will be
AddContent.Action.Text as the resource key. and when you try to call Localization.GetString(AddContent.Action, LocalResourceFile)

How to log complex synchronization process?

I'm developing a complicated distributed service that makes iterative synchronization process. It synchronise every 10 seconds business entities in different information systems. One iteration is consist of bunch of 3d party service calls to retrieve current state of business objects (count of customers, goods, certain customer and goods details etc.), queries to local DB and then get differences between them and smooth out, synchronize this differences.
There are different types of iterations. They are fast (only changes in set of objects) and slow iterations (full revieweing of data). Fast are every 10 seconds and slow are once a day.
So, how can I log this processes using NLog? I'm using SQLite for storing data. But I'm stuck in DB design for logs.
So I want to log flow of every iteration:
1. Request for current state of objects to 3d party service
2. Query the local database for current state of objects
3. Get differences list
4. Invoke external service to commit insufficient data
5. Update local database for insufficient data
But there is so many kinds of info to log so I can't just put it into one TEXT field.
At the moment I'm using such structure for logs:
CREATE TABLE [Log] (
[id] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
[ts] TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
[iteration_id] varchar,
[request_response_pair] varchar,
[type] VARCHAR NOT NULL,
[level] TEXT NOT NULL,
[server_id] VARCHAR,
[server_alias] VARCHAR,
[description] TEXT,
[error] Text);
So every service request and response puts to description and request_response_pair is a key to link every response to every request.
Here is my NLog config:
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" internalLogFile="D:\nlog.txt" internalLogLevel="Trace">
<targets>
<target name="Database" xsi:type="Database" keepConnection="false"
useTransactions="false"
dbProvider="System.Data.SQLite.SQLiteConnection, System.Data.SQLite, Version=1.0.82.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139"
connectionString="Data Source=${basedir}\SyncLog.db;Version=3;"
commandText="INSERT into Log(iteration_id, request_response_pair, type, level, server_id, server_alias, description, error) values(#Iteration_id, #Request_response_pair, #Type, #Loglevel, #server_id, #server_alias, #Description, #Error)">
<parameter name="#Type" layout="${message}"/>
<parameter name="#Loglevel" layout="${level:uppercase=true}"/>
<parameter name="#Request_response_pair" layout="${event-context:item=request_response_pair}"/>
<parameter name="#Iteration_id" layout="${event-context:item=iteration_id}"/>
<parameter name="#server_id" layout="${event-context:item=server_id}"/>
<parameter name="#server_alias" layout="${event-context:item=server_alias}"/>
<parameter name="#Description" layout="${event-context:item=description}"/>
<parameter name="#Error" layout="${event-context:item=error}"/>
</target>
</targets>
<rules>
<logger name="*" minlevel="Trace" writeTo="Database" />
</rules>
</nlog>
Here is how I log:
namespace NLog
{
public static class LoggerExtensions
{
public static void InfoEx(this Logger l, string message, Dictionary<string, object> contextParams)
{
LogEventInfo eventInfo = new LogEventInfo(LogLevel.Info, "", message);
foreach (KeyValuePair<string, object> kvp in contextParams)
{
eventInfo.Properties.Add(kvp.Key, kvp.Value);
}
l.Log(eventInfo);
}
public static void InfoEx(this Logger l, string message, string server_id, string server_alias, Dictionary<string, object> contextParams = null)
{
Dictionary<string, object> p = new Dictionary<string, object>();
p.Add("server_id", server_id);
p.Add("server_alias", server_alias);
if (contextParams != null)
{
foreach (KeyValuePair<string, object> kvp in contextParams)
{
p.Add(kvp.Key, kvp.Value);
}
}
l.InfoEx(message, p);
}
}
}
I know about logging levels but I need all this verbose logs, so I log it as info. I can't find any tutorial how to log these complicated, structured logs. Only plain dumb log messges.
I am assuming, you are talking about "Logs" for the typical "log things so we have something to look at if we need to inspect our workflow (errors/performance)". I assume that you do NOT mean logs as e.g. in "We need accounting information and the log is part of our domain data and is included in the workflow."
And from what I got from your posting, you are worrying about the backend storage format on the logs, so that you can later process them and use for said diagnostics?
Then I'd recommend that you make the logging code independend of the domain specifics.
Question: How will the logs you create be processed? Do you really need to access them all over the place so you need the database to provide you a structured view? Is it in any kind relevant how fast you can filter your logs? Or will they end up in one big log-analyzer application anyway, that is ran only ever second week when something bad happened?
In my opinion, the biggest reasons you want to avoid any domain specifics in the log are that "logs should work if things go wrong" and "logs should work after things changed".
Logs should work if things go wrong
If you have columns in your log table for domain specific values like "Request_response_pair", and there is no pair, then to write the log itself might fail (e.g. if its an index field). Of course, you can make sure to not have non-null columns and no restrictions in your DB-design, but take a step back and ask: Why do you want the structure in your log database anyway? Logs are meant to work as reliable as possible, so any kind of template you press them on may restrict the use cases or may make you not be able to log crucial information.
Logs should work after things changed
Especially if you need logs for detecting and fixing bugs or improve performance, that means that you will regulary compare logs from "before the change" to logs from "after the change". If you need to change the structure of your log database, because you changed your domain data, this is going to hurt you when you need to compare the logs.
True, if you make a data structure change, you probably still need to update some tools like log analyzer and such, but there is usually a large part of logging/analyzing code that is completely agnostic to the actual structure of the domain.
Many systems (including complex ones) can live with "just log one simple string" and later write tools to take the string apart again, if they need to filter or process the logs.
Other systems write logs in simple string key/value pairs. The log function itself is not domain specific but just accepts a string dictionary and writes it off (or even easier, a params string[] which should have an even number of parameters and you use every second parameter as key - if you aren't scared by that proposition :-D).
Of course, you will probably start writing another tooling layer on top of the base log functions that knows about domain specific data structures and then composes the string dictionary and pass it on. You certainly don't want to copy the decomposing code all place around. But make the base functions available at all places where you might want to log something. Its really helpfull if you indeed run into "strange" situations (exception handler) where some information is missing.

How do I read the IP address from a failed logon event in the event viewer using C#?

I'm trying to read the data from an Audit Failure event generated by a failed logon attempt. I can get the events I need, but I can't figure out how to actually get the IP address from the event.
To clarify, I want see the event generated by a failed windows logon attempt from a user. Looks like this in XML view in event log
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
<System>
<Provider Name="Microsoft-Windows-Security-Auditing" Guid="{54849625-5478-4994-A5BA-3E3B0328C30D}" />
<EventID>4625</EventID>
...
</System>
<EventData>
...
<Data Name="IpAddress">xxx.xxx.171.130</Data>
<Data Name="IpPort">50717</Data>
</EventData>
</Event>
In ASP.NET use:
Request.ServerVariables["REMOTE_ADDR"];
If you hid the actual ip address when posting by replacing the first two octets then just use xml or regex to read it in, but if it's exactly as you posted:
<Data Name="IpAddress">xxx.xxx.171.130</Data>
Then no, you can't from the event log, though if you're lucky and are in a small network with only one segment then you could figure it out.
For example if you're in a small network, you know there's only one segment you can incorporate that into your program's logic, like in your example ...171.130, if you know your network has an address in range 192.168.171.1-192.168.171.254 then you can be 100% certain that it came from 192.168.17.130, on the other hand if you know there is some other network in the range of 172.21.171.1-172.21.171.254 then you won't know, unless you know for sure, that the other segments cannot talk to your computer, you can usually ask your network people to find this out.
See this for a reference for ip and subnet calculations http://www.subnet-calculator.com/subnet.php?net_class=C
As ordag posted in the above question comment thread, the information I wanted was in the ReplacementStrings array.
Quote:
If you have the EventLogEntrys, the address should be a member of the
ReplacementStrings array property.

Reading the Windows Event Log with C# (Source != ProviderName != SourceName)

I am using C# to read the Windows Event Log and I want to select/filter entries from it. The problem is that the information displayed in the Event Viewer is not always matching the data I get from c#.
for example:
EventViewer "Source": "User Profile Service"
Using the EventLogEntry class: Property "Source": "Microsoft-Windows-User Profiles Service"
Using the EventLogReader class: Property "ProviderName": "Microsoft-Windows-User Profiles Service"
Using WMI: "SourceName": "Microsoft-Windows-User Profiles Service"
I need to be able to read the exact information displayed in the EventViewer, where can I get this information from?
Reading the EventLog message...
When reading the EventLog message using the EventLogEntry class I occasionally get the following string:
The description for Event ID "xxx" in Source "xxx" cannot be found
Again, this does not match the message displayed in the EventViewer... I have tried using the EventLogReader.FormatDescription() method and it gives me the right (the same as the EventViewer) message, BUT for some entries it simply returns null, while the EventLogEntry.Message contains the proper text.
What is the correct way to retrieve the message of the event to get the same message as the one displayed in the EventViewer?
var eventLog = new EventLog("logName", "machine", "source");
foreach(var entry in eventLog.Entries)
{
}
That is a fairly basic swag at interacting with the log. If you need deeper filtering that source, you can write a LINQ query on the Entries. As shown here.
As for the error, one common reason is not having the proper access to the events and/or registry on the box in question. Since you can see data in question in EventViewer, I am suspecting a permissions error is a good possibility.
It appears that the "Source" string shown in the "Source" column in the Event Viewer is abbreviated. Also it seems that when you try to create an EventLog in C# only the logtype matters e.g. "Application", "System" etc. Once you create an EventLog it will contain all the entries for that logtype regardless of what you specified a source.
In order to get an event based on "Source" you want to iterate over the entries and filter only the entries for that "Source". Just keep in mind that the actual source name is not the same as what you see in the Event Viewer. For example for Source "Winlogon" the actual source name would be: "Microsoft-Windows-Winlogon" and so on.

Categories

Resources