Guest User

Untitled

a guest
Nov 18th, 2017
72
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.50 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using Newtonsoft.Json;
  6. using Newtonsoft.Json.Linq;
  7.  
  8. class Solution {
  9. /// <summary>
  10. /// Types of messages we want to track
  11. /// </summary>
  12. public static readonly string[] TargetedMessages = { "Start Session", "Start Query", "End Query", "End Session", "Session started.", "Session ended.", "Query: Start", "Query: End" };
  13.  
  14. static void Main(string[] args)
  15. {
  16. var sessionCollection = new Dictionary<Guid, SessionInfo>();
  17.  
  18. // Loop through rows
  19. string row = string.Empty;
  20. do
  21. {
  22. try
  23. {
  24. row = Console.ReadLine();
  25. if (string.IsNullOrEmpty(row)) continue;
  26.  
  27. LogEntry entry;
  28.  
  29. if (row.StartsWith("{") && row.EndsWith("}"))
  30. {
  31. try
  32. {
  33. entry = JsonConvert.DeserializeObject<LogEntry>(row);
  34. }
  35. catch { continue; } // Continue if deserialization failed
  36. }
  37. else
  38. {
  39. if (row.Length < 66) continue; // rows should be at least 66 characters long. If not, continue
  40. if (!DateTime.TryParse(row.Substring(0, 25), out var timeStamp)) continue; // Continue if timestamp parsing failed
  41. if (!Guid.TryParse(row.Substring(26, 36), out var sessionId)) continue; // Continue if guid parsing failed
  42. var durationEndIndex = row.IndexOf(' ', 63);
  43. if (durationEndIndex == -1) continue; // Continue if misformatted row
  44. if (!long.TryParse(row.Substring(63, durationEndIndex - 63), out var duration)) continue; // Continue if duration parsing failed
  45. if (durationEndIndex + 1 >= row.Length) continue; // Continue if empty message
  46. var message = row.Substring(durationEndIndex + 1);
  47.  
  48. entry = new LogEntry(timeStamp, sessionId, duration, message);
  49. }
  50.  
  51. if (entry == null
  52. || entry.Timestamp == null
  53. || string.IsNullOrEmpty(entry.Message)
  54. || !entry.Session.HasValue
  55. || entry.Session.Value == Guid.Empty) continue; // Continue if the entry is missing information
  56.  
  57.  
  58. if (sessionCollection.TryGetValue(entry.Session.Value, out var session))
  59. {
  60. // If session is already in the collection, add a new LogEntry to it
  61. session.AddEntry(entry);
  62. }
  63. else
  64. {
  65. // If session was not found, let's add one
  66. sessionCollection.Add(entry.Session.Value, new SessionInfo(entry));
  67. }
  68. }
  69. catch { }
  70. } while (!string.IsNullOrEmpty(row));
  71.  
  72. // Extract only the values from our dictionary, order them and serialize
  73. var resultString = JsonConvert.SerializeObject(sessionCollection.Values
  74. .OrderBy(x => x.StartTimestampUtc)
  75. .ThenBy(x => x.TotalDuration)
  76. .ToList(),
  77. Formatting.None,
  78. new JsonSerializerSettings() {
  79. DateTimeZoneHandling = DateTimeZoneHandling.Utc
  80. });
  81.  
  82. // Format the result
  83. var formatted = JValue.Parse(resultString).ToString(Formatting.Indented);
  84.  
  85. Console.Write(formatted);
  86. }
  87.  
  88. /// <summary>
  89. /// Class that stores session information.
  90. /// </summary>
  91. public class SessionInfo
  92. {
  93. [JsonProperty(PropertyName = "startTimestampUtc")]
  94. public DateTime? StartTimestampUtc { get; set; }
  95.  
  96. [JsonProperty(PropertyName = "endTimestampUtc")]
  97. public DateTime? EndTimestampUtc { get; set; }
  98.  
  99. [JsonProperty(PropertyName = "sessionId"), JsonConverter(typeof(GuidToStringConverter))]
  100. public Guid SessionId { get; set; }
  101.  
  102. [JsonProperty(PropertyName = "totalDuration")]
  103. public long TotalDuration { get; set; }
  104.  
  105. [JsonProperty(PropertyName = "queryCount")]
  106. public long QueryCount
  107. {
  108. get
  109. {
  110. int count = 0, endIdx = 0;
  111. var startedQueries = LogEntries.Where(x => x.Message == ("Query: Start") || x.Message == "Start Query").OrderBy(x => x.Timestamp).Select(x => x.Timestamp).ToArray();
  112. var endedQueries = LogEntries.Where(x => x.Message == ("Query: End") || x.Message == "End Query").OrderBy(x => x.Timestamp).Select(x => x.Timestamp).ToArray();
  113.  
  114. for(var i = 0; i < startedQueries.Length; i++)
  115. {
  116. for(var e = endIdx; e < endedQueries.Length; e++)
  117. {
  118. if (endedQueries[e] >= startedQueries[i])
  119. {
  120. count++;
  121. endIdx = e + 1;
  122. break;
  123. }
  124. if (count == endedQueries.Length || endIdx == endedQueries.Length) return count;
  125. }
  126. }
  127.  
  128. return count;
  129. }
  130. }
  131. [JsonIgnore]
  132. public List<LogEntry> LogEntries { get; set; }
  133.  
  134. /// <summary>
  135. /// Constructor that takes in the initial LogEntry and builds the initial SessionInfo object.
  136. /// </summary>
  137. /// <param name="entry">The entry to process</param>
  138. public SessionInfo(LogEntry entry)
  139. {
  140. SessionId = entry.Session ?? Guid.Empty;
  141. TotalDuration = entry.Duration ?? 0;
  142.  
  143. RecordStartEndTimestamp(entry);
  144.  
  145. LogEntries = new List<LogEntry>() { entry };
  146. }
  147.  
  148. /// <summary>
  149. /// Method for adding a LogEntry to a SessionInfo object.
  150. /// </summary>
  151. /// <param name="entry">The entry to process</param>
  152. public void AddEntry(LogEntry entry)
  153. {
  154. RecordStartEndTimestamp(entry);
  155.  
  156. TotalDuration += entry.Duration ?? 0;
  157. LogEntries.Add(entry);
  158. }
  159.  
  160. /// <summary>
  161. /// Private method that evaluates the log message and makes changes to the start/end timetamps when required.
  162. /// </summary>
  163. /// <param name="entry">The entry to process</param>
  164. private void RecordStartEndTimestamp(LogEntry entry)
  165. {
  166. if (entry.Message == "Session started." || entry.Message == "Start Session")
  167. {
  168. StartTimestampUtc = entry.Timestamp;
  169. }
  170. else if (entry.Message == "Session ended." || entry.Message == "End Session")
  171. {
  172. EndTimestampUtc = entry.Timestamp;
  173. }
  174. }
  175. }
  176.  
  177. /// <summary>
  178. /// Class that holds information about individual log entries
  179. /// </summary>
  180. public class LogEntry
  181. {
  182. [JsonProperty(PropertyName = "t")]
  183. public DateTime? Timestamp { get; set; }
  184.  
  185. [JsonProperty(PropertyName = "s")]
  186. public Guid? Session { get; set; }
  187.  
  188. [JsonProperty(PropertyName = "d")]
  189. public long? Duration { get; set; }
  190.  
  191. [JsonProperty(PropertyName = "m")]
  192. public string Message { get; set; }
  193.  
  194. [JsonProperty(PropertyName = "r")]
  195. public long? ResultCount { get; set; }
  196.  
  197. [JsonProperty(PropertyName = "cache-hit")]
  198. public bool? CacheHit { get; set; }
  199.  
  200. public LogEntry() { }
  201.  
  202. /// <summary>
  203. /// LogEntry constructor that parses the log message for cache hits and results
  204. /// </summary>
  205. /// <param name="timeStamp">The timestamp</param>
  206. /// <param name="session">Session Id Guid</param>
  207. /// <param name="duration">Duration in ms</param>
  208. /// <param name="message">The message</param>
  209. public LogEntry(DateTime timeStamp, Guid session, long duration, string message)
  210. {
  211. Timestamp = timeStamp;
  212. Session = session;
  213. Duration = duration;
  214.  
  215. if (message.StartsWith("Start Query (cache-hit:"))
  216. {
  217. if (bool.TryParse(message.Substring(23, message.Length - 24), out var cache))
  218. CacheHit = cache;
  219. else
  220. {
  221. Session = null;
  222. }
  223. Message = "Start Query";
  224. }
  225. else if (message.StartsWith("End Query (results:"))
  226. {
  227. if (long.TryParse(message.Substring(20, message.Length - 21), out var results))
  228. ResultCount = results;
  229. else
  230. {
  231. Session = null;
  232. }
  233. Message = "End Query";
  234. }
  235. else Message = message;
  236. }
  237. }
  238.  
  239. /// <summary>
  240. /// Custom Json converter for Guids
  241. /// </summary>
  242. public class GuidToStringConverter : JsonConverter
  243. {
  244. public override bool CanConvert(Type objectType)
  245. {
  246. return true;
  247. }
  248. public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
  249. {
  250. writer.WriteValue(((Guid)value).ToString("N"));
  251. }
  252. public override bool CanRead { get { return false; } }
  253.  
  254. public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
  255. {
  256. throw new NotImplementedException();
  257. }
  258. }
  259. }
Add Comment
Please, Sign In to add comment