1+ using System ;
2+ using System . Linq ;
3+ using System . Net . Http ;
4+ using System . Threading ;
5+ using Microsoft . Extensions . Logging ;
6+ using Splunk ;
7+
8+ namespace Vtex . SplunkLogger
9+ {
10+ /// <summary>
11+ /// This class contains all methods to format a Log event into a VTEX standard text.
12+ /// </summary>
13+ /// <remarks>
14+ /// At our Splunk environment at VTEX we expect certain standard of text to be processed and
15+ /// we also have field extraction rules to be applied.
16+ /// Thats the reason why we use a custom LoggerFormmater.
17+ /// </remarks>
18+ public class VTEXSplunkLoggerFormatter : ILoggerFormatter
19+ {
20+ const string DateTimeFormat = "yyyy-MM-ddTHH:mm:ss.fffZ" ;
21+
22+ readonly string appVersion ;
23+ readonly string host ;
24+
25+ /// <summary>
26+ /// Initializes a new instance of the <see cref="T:VTEX.SampleWebAPI.Logging.VTEXSplunkLoggerFormatter"/> class.
27+ /// </summary>
28+ public VTEXSplunkLoggerFormatter ( )
29+ {
30+ appVersion = Microsoft . Extensions . PlatformAbstractions . PlatformServices . Default . Application . ApplicationVersion ;
31+ host = GetHost ( ) ;
32+ }
33+
34+ /// <summary>
35+ /// Format the specified logLevel, eventId, state and exception into log string entry.
36+ /// </summary>
37+ /// <returns>Formatted log string.</returns>
38+ /// <param name="logLevel">Log level.</param>
39+ /// <param name="eventId">Event identifier.</param>
40+ /// <param name="state">Log object state.</param>
41+ /// <param name="exception">Log exception.</param>
42+ /// <typeparam name="T">Log entry.</typeparam>
43+ public string Format < T > ( LogLevel logLevel , EventId eventId , T state , Exception exception )
44+ {
45+ string log ;
46+ if ( state is VTEXSplunkEntry )
47+ {
48+ var splunkEntry = state as VTEXSplunkEntry ;
49+ var dateTime = DateTime . UtcNow . ToString ( DateTimeFormat ) ;
50+ string extraData = string . Empty ;
51+ if ( splunkEntry . ExtraParameters != null && splunkEntry . ExtraParameters . Count > 0 )
52+ extraData = string . Join ( " " , splunkEntry . ExtraParameters . Select ( part => { return $ "{ part . Item1 } =\" { part . Item2 } \" "; } ) ) ;
53+ string account = splunkEntry . Account ;
54+ if ( string . IsNullOrWhiteSpace ( splunkEntry . Account ) )
55+ account = "-" ;
56+ log = string . Format ( $ "{ dateTime } VTEXLog,splunkmanager,{ host } ,{ GetVTEXEventLevel ( logLevel ) } ,{ GetVTEXLogType ( logLevel ) } ,\" { splunkEntry . WorkflowType } \" ,\" { splunkEntry . WorkflowInstance } \" ,{ account } ,{ appVersion } { extraData } ") ;
57+ }
58+ else
59+ {
60+ var eventSegment = "" ;
61+ if ( ! string . IsNullOrWhiteSpace ( eventId . Name ) )
62+ eventSegment = $ "Event '{ eventId . Name } ' on { eventId . Id } ";
63+ var exceptionSegment = "" ;
64+ if ( exception != null )
65+ exceptionSegment = $ "Exception type: { exception . GetType ( ) . FullName } . Exception message: { exception . Message } ";
66+ log = string . Format ( $ "[{ logLevel } ] { eventSegment } { state . ToString ( ) } . { exceptionSegment } ") ;
67+ }
68+ return log ;
69+ }
70+
71+ /// <summary>
72+ /// Formats the specified logLevel, eventId, state and exception into json entry.
73+ /// </summary>
74+ /// <returns>The json.</returns>
75+ /// <param name="logLevel">Log level.</param>
76+ /// <param name="eventId">Event identifier.</param>
77+ /// <param name="state">Log object state.</param>
78+ /// <param name="exception">Log exception.</param>
79+ /// <typeparam name="T">Log entry.</typeparam>
80+ public SplunkJSONEntry FormatJson < T > ( LogLevel logLevel , EventId eventId , T state , Exception exception )
81+ {
82+ return new SplunkJSONEntry ( Format ( logLevel , eventId , state , exception ) , 0 , host , string . Empty , "Log" ) ;
83+ }
84+
85+ /// <summary>
86+ /// Method created to get AWS EC2 host Id, or set `dev` as host if AWS internal call fails.
87+ /// </summary>
88+ string GetHost ( )
89+ {
90+ string ec2Host = string . Empty ;
91+ try
92+ {
93+ using ( HttpClient httpClient = new HttpClient ( ) )
94+ {
95+ TimeSpan timeSpan = new TimeSpan ( 0 , 0 , 5 ) ;
96+ var cancellationTokenSource = new CancellationTokenSource ( ( int ) timeSpan . TotalMilliseconds ) ;
97+ httpClient . Timeout = timeSpan ;
98+ httpClient . BaseAddress = new Uri ( "http://169.254.169.254/latest/meta-data/" ) ;
99+ ec2Host = httpClient
100+ . GetAsync ( "instance-id" , cancellationTokenSource . Token )
101+ . Result
102+ . Content
103+ . ReadAsStringAsync ( )
104+ . Result ;
105+ }
106+ }
107+ catch
108+ {
109+ ec2Host = "dev" ;
110+ }
111+ return ec2Host ;
112+ }
113+
114+ /// <summary>
115+ /// Based on LogLevel we define the correspondent VTEX event level.
116+ /// </summary>
117+ /// <returns>VTEX event level.</returns>
118+ string GetVTEXEventLevel ( LogLevel logLevel )
119+ {
120+ VTEXEventLevel eventLevel = VTEXEventLevel . Debug ;
121+ switch ( logLevel )
122+ {
123+ case LogLevel . Critical :
124+ eventLevel = VTEXEventLevel . Critical ;
125+ break ;
126+ case LogLevel . Warning :
127+ case LogLevel . Error :
128+ eventLevel = VTEXEventLevel . Important ;
129+ break ;
130+ case LogLevel . Information :
131+ eventLevel = VTEXEventLevel . Default ;
132+ break ;
133+ case LogLevel . Trace :
134+ case LogLevel . Debug :
135+ case LogLevel . None :
136+ eventLevel = VTEXEventLevel . Debug ;
137+ break ;
138+ }
139+ return eventLevel . ToString ( ) . ToLower ( ) ;
140+ }
141+
142+ /// <summary>
143+ /// Based on LogLevel we define the correspondent VTEX log type.
144+ /// </summary>
145+ /// <returns>VTEX log type.</returns>
146+ string GetVTEXLogType ( LogLevel logLevel )
147+ {
148+ VTEXLogType logType = VTEXLogType . Info ;
149+ switch ( logLevel )
150+ {
151+ case LogLevel . Critical :
152+ case LogLevel . Error :
153+ logType = VTEXLogType . Error ;
154+ break ;
155+ case LogLevel . Warning :
156+ logType = VTEXLogType . Warning ;
157+ break ;
158+ case LogLevel . Debug :
159+ case LogLevel . Information :
160+ case LogLevel . Trace :
161+ case LogLevel . None :
162+ logType = VTEXLogType . Info ;
163+ break ;
164+ }
165+ return logType . ToString ( ) . ToLower ( ) ;
166+ }
167+ }
168+ }
0 commit comments