1+ // Copyright 2016 Serilog Contributors 
2+ // 
3+ // Licensed under the Apache License, Version 2.0 (the "License"); 
4+ // you may not use this file except in compliance with the License. 
5+ // You may obtain a copy of the License at 
6+ // 
7+ //     http://www.apache.org/licenses/LICENSE-2.0 
8+ // 
9+ // Unless required by applicable law or agreed to in writing, software 
10+ // distributed under the License is distributed on an "AS IS" BASIS, 
11+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
12+ // See the License for the specific language governing permissions and 
13+ // limitations under the License. 
14+ 
15+ using  Serilog . Events ; 
16+ using  Serilog . Formatting ; 
17+ using  Serilog . Formatting . Json ; 
18+ using  Serilog . Parsing ; 
19+ using  System ; 
20+ using  System . Globalization ; 
21+ using  System . IO ; 
22+ using  System . Linq ; 
23+ 
24+ namespace  Serilog . Sinks . Splunk 
25+ { 
26+     /// <summary> 
27+     /// Renders log events into a Compact JSON format for consumption by Splunk. 
28+     /// </summary> 
29+     public  class  CompactSplunkJsonFormatter  :  ITextFormatter 
30+     { 
31+         private  static   readonly  JsonValueFormatter  ValueFormatter  =  new  JsonValueFormatter ( typeTagName :  "$type" ) ; 
32+         private  readonly  string  _suffix ; 
33+         private  readonly  bool  _renderTemplate ; 
34+ 
35+         /// <summary> 
36+         /// Construct a <see cref="CompactSplunkJsonFormatter"/>. 
37+         /// </summary> 
38+         /// <param name="source">The source of the event</param> 
39+         /// <param name="sourceType">The source type of the event</param> 
40+         /// <param name="host">The host of the event</param> 
41+         /// <param name="index">The Splunk index to log to</param> 
42+         /// <param name="renderTemplate">If true, the template used will be rendered and written to the output as a property named MessageTemplate</param> 
43+         public  CompactSplunkJsonFormatter ( bool  renderTemplate  =  false ,  string  source  =  null ,  string  sourceType  =  null ,  string  host  =  null ,  string  index  =  null ) 
44+         { 
45+             _renderTemplate  =  renderTemplate ; 
46+             var  suffixWriter  =  new  StringWriter ( ) ; 
47+             suffixWriter . Write ( "}" ) ;  // Terminates "event" 
48+ 
49+             if  ( ! string . IsNullOrWhiteSpace ( source ) ) 
50+             { 
51+                 suffixWriter . Write ( ",\" source\" :" ) ; 
52+                 JsonValueFormatter . WriteQuotedJsonString ( source ,  suffixWriter ) ; 
53+             } 
54+ 
55+             if  ( ! string . IsNullOrWhiteSpace ( sourceType ) ) 
56+             { 
57+                 suffixWriter . Write ( ",\" sourcetype\" :" ) ; 
58+                 JsonValueFormatter . WriteQuotedJsonString ( sourceType ,  suffixWriter ) ; 
59+             } 
60+ 
61+             if  ( ! string . IsNullOrWhiteSpace ( host ) ) 
62+             { 
63+                 suffixWriter . Write ( ",\" host\" :" ) ; 
64+                 JsonValueFormatter . WriteQuotedJsonString ( host ,  suffixWriter ) ; 
65+             } 
66+ 
67+             if  ( ! string . IsNullOrWhiteSpace ( index ) ) 
68+             { 
69+                 suffixWriter . Write ( ",\" index\" :" ) ; 
70+                 JsonValueFormatter . WriteQuotedJsonString ( index ,  suffixWriter ) ; 
71+             } 
72+             suffixWriter . Write ( '}' ) ;  // Terminates the payload 
73+             _suffix  =  suffixWriter . ToString ( ) ; 
74+         } 
75+ 
76+         /// <inheritdoc/> 
77+         public  void  Format ( LogEvent  logEvent ,  TextWriter  output ) 
78+         { 
79+             if  ( logEvent  ==  null )  throw  new  ArgumentNullException ( nameof ( logEvent ) ) ; 
80+             if  ( output  ==  null )  throw  new  ArgumentNullException ( nameof ( output ) ) ; 
81+ 
82+             output . Write ( "{\" time\" :\" " ) ; 
83+             output . Write ( logEvent . Timestamp . ToEpoch ( ) . ToString ( CultureInfo . InvariantCulture ) ) ; 
84+             output . Write ( "\" ,\" event\" :{\" @l\" :\" " ) ; 
85+             output . Write ( logEvent . Level ) ; 
86+             output . Write ( '"' ) ; 
87+ 
88+             if  ( _renderTemplate ) 
89+             { 
90+                 output . Write ( ",\" @mt\" :" ) ; 
91+                 JsonValueFormatter . WriteQuotedJsonString ( logEvent . MessageTemplate . Text ,  output ) ; 
92+ 
93+                 var  tokensWithFormat  =  logEvent . MessageTemplate . Tokens 
94+                     . OfType < PropertyToken > ( ) 
95+                     . Where ( pt =>  pt . Format  !=  null ) ; 
96+ 
97+                 // Better not to allocate an array in the 99.9% of cases where this is false 
98+                 // ReSharper disable once PossibleMultipleEnumeration 
99+                 if  ( tokensWithFormat . Any ( ) ) 
100+                 { 
101+                     output . Write ( ",\" @r\" :[" ) ; 
102+                     var  delim  =  "" ; 
103+                     foreach  ( var  r  in  tokensWithFormat ) 
104+                     { 
105+                         output . Write ( delim ) ; 
106+                         delim  =  "," ; 
107+                         var  space  =  new  StringWriter ( ) ; 
108+                         r . Render ( logEvent . Properties ,  space ) ; 
109+                         JsonValueFormatter . WriteQuotedJsonString ( space . ToString ( ) ,  output ) ; 
110+                     } 
111+                     output . Write ( ']' ) ; 
112+                 } 
113+             } 
114+             if  ( logEvent . Exception  !=  null ) 
115+             { 
116+                 output . Write ( ",\" @x\" :" ) ; 
117+                 JsonValueFormatter . WriteQuotedJsonString ( logEvent . Exception . ToString ( ) ,  output ) ; 
118+             } 
119+ 
120+             foreach  ( var  property  in  logEvent . Properties ) 
121+             { 
122+                 var  name  =  property . Key ; 
123+                 if  ( name . Length  >  0  &&  name [ 0 ]  ==  '@' ) 
124+                 { 
125+                     // Escape first '@' by doubling 
126+                     name  =  '@'  +  name ; 
127+                 } 
128+ 
129+                 output . Write ( ',' ) ; 
130+                 JsonValueFormatter . WriteQuotedJsonString ( name ,  output ) ; 
131+                 output . Write ( ':' ) ; 
132+                 ValueFormatter . Format ( property . Value ,  output ) ; 
133+             } 
134+             output . WriteLine ( _suffix ) ; 
135+         } 
136+     } 
137+ } 
0 commit comments