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