0

I'm using Newtonsoft JSON in C#.

I have a log file which I am trying to parse so I can populate a database with the data in the log file.

In the log file, each line is a separate JSON object.

Here is what the log file looks like:

{ "timestamp":"2020-02-02T04:49:53Z", "event":"Friends", "Status":"Online", "Name":"User1" }
{ "timestamp":"2020-02-02T04:48:06Z", "event":"Commander", "FID":"F2", "Name":"User2" }
{ "timestamp":"2020-02-02T04:48:06Z", "event":"Materials", "Raw":[ { "Name":"cadmium", "Count":9},
      { "Name":"zinc", "Count":45 }, { "Name":"iron", "Count":71 }]}

Here's what I'm doing so far:

var fullPath = @"X:\Data\Log Files\test log.log";
string[] lines = File.ReadAllLines(fullPath);

            foreach (var line in lines)
        {
            var json = JObject.Parse(line);
            var eventType = json["event"].Value<string>();

            JArray raw = (JArray)line["Raw"];

            switch (eventType)
               {
                case "Friends":

                    var status = json["Status"].Value<string>();
                    var frName = json["Name"].Value<string>();

                    Console.WriteLine("The friend " + frName + " is currently " + status + ".");

                    Console.WriteLine(json);

                    break;

                case "Commander":

                    var fid = json["FID"].Value<string>();
                    var CMDR = json["Name"].Value<string>();

                    Console.WriteLine("User " + CMDR + " with ID " + ".");

                    Console.WriteLine(json);

                    break;

                case "Materials":


                    //do something here that is magical.

                    break;

                default:
                    Console.WriteLine("N/A");
                    break;
            }

The first two cases work fine. However, I can't figure out how to get the array "Raw" out of the "Materials" event.

FYI - there are two other arrays in that line. So, I need to be able to extract the array for "Raw" as well as the others.

So far, I just can't figure this out.

I'm very much a beginner, so please explain this as if you were talking to a toddler. :)

please help with this?

Thanks so much!

1

5 Answers 5

4

All of the answers above are completely valid for the question you're asking, however, for better code readability and debugging you're better converting those json strings to actual c# objects. For example you'd set up some models like this:

public class Friends
{
    public string Timestamp { get; set; }
    public string Event { get; set; }
    public string Status { get; set; }
    public string Name { get; set; }
}

public class Commander
{
    public string Timestamp { get; set; }
    public string Event { get; set; }
    public string FID { get; set; }
    public string Name { get; set; }
}

public class Materials
{
    public string Timestamp { get; set; }
    public string Event { get; set; }
    public List<Material> Raw { get; set; }
}

public class Material
{
    public string Name { get; set; }
    public string Count { get; set; }
}

You'd have 1 model for each of your different log types. Now in your logic what you want to do is read the event type from the JSON and then turn that into a valid c# type (in my code below I use a dictionary) and then use that type to tell the JsonConvert.DeserializeObject method what to convert your json string into, this is how I implemented it:

//Same as your code
        var fullPath = @"C:\testLog.log";
        string[] lines = File.ReadAllLines(fullPath);

        //This dictionary stores each of your different log types in a way where you can use the "event" string in each json to get the c# object type
        Dictionary<string, Type> types = new Dictionary<string, Type>()
        {
            { "Friends", typeof(Friends)},
            {"Commander", typeof(Commander) },
            {"Materials", typeof(Materials) }
        };

        foreach (var line in lines)
        {
            //Same as your code
            var json = JObject.Parse(line);
            Type eventType = types[json["event"].Value<string>()];

            //This line will use the event type provided by the json to deserialise your object
            var x = JsonConvert.DeserializeObject(line, eventType);

            switch (x)
            {
                case Friends friendObject:
                    //Do stuff with the friend object here
                    Console.WriteLine("Friend log found");
                    Console.WriteLine(friendObject.Timestamp);
                    Console.WriteLine(friendObject.Name);
                    Console.WriteLine(friendObject.Status);
                    Console.WriteLine();
                    break;
                case Commander commanderObject:
                    //Do stuff with the commander object here
                    Console.WriteLine("Commander log found");
                    Console.WriteLine(commanderObject.Timestamp);
                    Console.WriteLine(commanderObject.FID);
                    Console.WriteLine(commanderObject.Name);
                    Console.WriteLine();
                    break;
                case Materials materialsObject:
                    //do stuff with the material object here
                    Console.WriteLine("Materials log found");
                    Console.WriteLine(materialsObject.Timestamp);
                    materialsObject.Raw.ForEach(material=>Console.WriteLine(material.Name + ". Count: " + material.Count));
                    break;
            }
        }
Sign up to request clarification or add additional context in comments.

Comments

1

You could do the following.

  var eventType = json["event"].Value<string>();
  Console.WriteLine($"Event Type {eventType}");
  foreach(var obj in json["Raw"])
  {
    Console.WriteLine($"Name={obj["Name"]},Count = {obj["Count"]}");
  }

You are in this case, parsing the "Raw" array from the Json Object and iterating over the JObjects to fetch each element in the array

Comments

0

You need to parse an array of JToken. Please try this :

foreach (var line in lines)
        {
            var json = JObject.Parse(line);
            var eventType = json["event"].Value<string>();


            switch (eventType)
            {
                case "Friends":

                    var status = json["Status"].Value<string>();
                    var frName = json["Name"].Value<string>();

                    Console.WriteLine("The friend " + frName + " is currently " + status + ".");

                    Console.WriteLine(json);

                    break;

                case "Commander":

                    var fid = json["FID"].Value<string>();
                    var CMDR = json["Name"].Value<string>();

                    Console.WriteLine("User " + CMDR + " with ID " + ".");

                    Console.WriteLine(json);

                    break;

                case "Materials":
                    var raw = JArray.Parse(json["Raw"].ToString());

                    foreach(JToken token in raw)
                    {
                        Console.WriteLine("Name " + token["Name"] + " Counter " + token["Count"]);
                    }


                    break;

                default:
                    Console.WriteLine("N/A");
                    break;
            }
        }

Hope it will help you.

Comments

0

Instead of going line by line, I suggest to ReadAllText and loop the JsonArray

var json = JArray.Parse(File.ReadAllText(fullPath));
foreach (var jsonItem in json)
{
    var eventType = jsonItem["event"].ToString();
    switch (eventType)
    {
        case "Friends":
            var status = jsonItem["Status"].Value<string>();
            var frName = jsonItem["Name"].Value<string>();
            Console.WriteLine("The friend " + frName + " is currently " + status + ".");
            break;
        case "Commander":
            var fid = jsonItem["FID"].Value<string>();
            var CMDR = jsonItem["Name"].Value<string>();
            Console.WriteLine("User " + CMDR + " with ID " + ".");
            break;
        case "Materials":
            //Your magic code here
            var raw = JArray.Parse(jsonItem["Raw"].ToString());
            foreach (var rawItem in raw)
            {
                Console.WriteLine("Name " + rawItem["Name"] + " with Count " + rawItem["Count"] + ".");
            }
            break;
        default:
            Console.WriteLine("N/A");
            break;
    }
}

Comments

0

Thank you all for your answers.

I ended up doing something close to what Coffee suggested.

First, I added a class file to my solution. Then, copied the JSON string and did "Edit>Paste Special>Paste JSON as Classes" which created this:

public class Materials
{
public DateTime timestamp { get; set; }
public string _event { get; set; }
public Raw[] Raw { get; set; }
}

public class Raw
{
public string Name { get; set; }
public int Count { get; set; }
}

Then, I deserialized the object into a list:

{
case "Materials":

//do something here that is magical.

Materials m = JsonConvert.DeserializeObject<Materials>(line);
List<Raw> r = m.Raw.ToList();

break;
}

This seemed to do the trick. What do you guys think?

1 Comment

Looks good, I'd definitely recommend doing this for all your logs so that let's say in future you want to add an extra property to one of the logs, you can just add it to the class and that's it, no need to manually write the code to get the data out

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.