1
1
using System ;
2
+ using System . Diagnostics ;
3
+ using System . Globalization ;
4
+ using System . Linq ;
5
+ using System . Net ;
6
+ #if ! PORTABLE && ! NETSTANDARD1_2
7
+ using System . Net . Sockets ;
8
+ #endif
9
+ using System . Runtime . InteropServices ;
10
+ using System . Text ;
11
+ using System . Threading ;
12
+ using Exceptionless . Logging ;
2
13
using Exceptionless . Models . Data ;
3
14
4
15
namespace Exceptionless . Services {
5
16
public class DefaultEnvironmentInfoCollector : IEnvironmentInfoCollector {
6
17
private static EnvironmentInfo _environmentInfo ;
18
+ private readonly IExceptionlessLog _log ;
19
+
20
+ public DefaultEnvironmentInfoCollector ( IExceptionlessLog log ) {
21
+ _log = log ;
22
+ }
7
23
8
24
public EnvironmentInfo GetEnvironmentInfo ( ) {
9
- if ( _environmentInfo == null )
10
- _environmentInfo = new EnvironmentInfo {
11
- MachineName = Guid . NewGuid ( ) . ToString ( "N" ) ,
12
- } ;
25
+ if ( _environmentInfo != null ) {
26
+ PopulateThreadInfo ( _environmentInfo ) ;
27
+ PopulateMemoryInfo ( _environmentInfo ) ;
28
+ return _environmentInfo ;
29
+ }
30
+
31
+ var info = new EnvironmentInfo ( ) ;
32
+ PopulateRuntimeInfo ( info ) ;
33
+ PopulateProcessInfo ( info ) ;
34
+ PopulateThreadInfo ( info ) ;
35
+ PopulateMemoryInfo ( info ) ;
13
36
37
+ _environmentInfo = info ;
14
38
return _environmentInfo ;
15
39
}
40
+
41
+ private void PopulateApplicationInfo ( EnvironmentInfo info ) {
42
+ #if NET45 || NETSTANDARD1_5
43
+ try {
44
+ info . Data . Add ( "AppDomainName" , AppDomain . CurrentDomain . FriendlyName ) ;
45
+ } catch ( Exception ex ) {
46
+ _log . FormattedInfo ( typeof ( EnvironmentInfoCollector ) , "Unable to get AppDomain friendly name. Error message: {0}" , ex . Message ) ;
47
+ }
48
+ #endif
49
+
50
+ #if ! PORTABLE && ! NETSTANDARD1_2
51
+ try {
52
+ IPHostEntry hostEntry = Dns . GetHostEntryAsync ( Dns . GetHostName ( ) ) . ConfigureAwait ( false ) . GetAwaiter ( ) . GetResult ( ) ;
53
+ if ( hostEntry != null && hostEntry . AddressList . Any ( ) )
54
+ info . IpAddress = String . Join ( ", " , hostEntry . AddressList . Where ( x => x . AddressFamily == AddressFamily . InterNetwork ) . Select ( a => a . ToString ( ) ) . ToArray ( ) ) ;
55
+ } catch ( Exception ex ) {
56
+ _log . FormattedInfo ( typeof ( EnvironmentInfoCollector ) , "Unable to get ip address. Error message: {0}" , ex . Message ) ;
57
+ }
58
+ #endif
59
+ }
60
+
61
+ private void PopulateProcessInfo ( EnvironmentInfo info ) {
62
+ try {
63
+ info . ProcessorCount = Environment . ProcessorCount ;
64
+ } catch ( Exception ex ) {
65
+ _log . FormattedInfo ( typeof ( EnvironmentInfoCollector ) , "Unable to get processor count. Error message: {0}" , ex . Message ) ;
66
+ }
67
+
68
+ #if ! PORTABLE && ! NETSTANDARD1_2
69
+ try {
70
+ Process process = Process . GetCurrentProcess ( ) ;
71
+ info . ProcessName = process . ProcessName ;
72
+ info . ProcessId = process . Id . ToString ( NumberFormatInfo . InvariantInfo ) ;
73
+ } catch ( Exception ex ) {
74
+ _log . FormattedInfo ( typeof ( EnvironmentInfoCollector ) , "Unable to get process name or id. Error message: {0}" , ex . Message ) ;
75
+ }
76
+
77
+ try {
78
+ #if NETSTANDARD1_5
79
+ info . CommandLine = String . Join ( " " , Environment . GetCommandLineArgs ( ) ) ;
80
+ #elif NET45
81
+ info . CommandLine = Environment . CommandLine ;
82
+ #endif
83
+ } catch ( Exception ex ) {
84
+ _log . FormattedInfo ( typeof ( EnvironmentInfoCollector ) , "Unable to get command line. Error message: {0}" , ex . Message ) ;
85
+ }
86
+ #endif
87
+ }
88
+
89
+ private void PopulateThreadInfo ( EnvironmentInfo info ) {
90
+ #if ! PORTABLE && ! NETSTANDARD1_2
91
+ try {
92
+ info . ThreadId = Thread . CurrentThread . ManagedThreadId . ToString ( NumberFormatInfo . InvariantInfo ) ;
93
+ } catch ( Exception ex ) {
94
+ _log . FormattedInfo ( typeof ( EnvironmentInfoCollector ) , "Unable to get thread id. Error message: {0}" , ex . Message ) ;
95
+ }
96
+
97
+ try {
98
+ info . ThreadName = Thread . CurrentThread . Name ;
99
+ } catch ( Exception ex ) {
100
+ _log . FormattedInfo ( typeof ( EnvironmentInfoCollector ) , "Unable to get current thread name. Error message: {0}" , ex . Message ) ;
101
+ }
102
+ #endif
103
+ }
104
+
105
+ private void PopulateMemoryInfo ( EnvironmentInfo info ) {
106
+ #if ! PORTABLE && ! NETSTANDARD1_2
107
+ try {
108
+ Process process = Process . GetCurrentProcess ( ) ;
109
+ info . ProcessMemorySize = process . PrivateMemorySize64 ;
110
+ } catch ( Exception ex ) {
111
+ _log . FormattedInfo ( typeof ( EnvironmentInfoCollector ) , "Unable to get process memory size. Error message: {0}" , ex . Message ) ;
112
+ }
113
+ #endif
114
+
115
+ #if NET45
116
+ try {
117
+ if ( IsMonoRuntime ) {
118
+ if ( PerformanceCounterCategory . Exists ( "Mono Memory" ) ) {
119
+ var totalPhysicalMemory = new PerformanceCounter ( "Mono Memory" , "Total Physical Memory" ) ;
120
+ info . TotalPhysicalMemory = Convert . ToInt64 ( totalPhysicalMemory . RawValue ) ;
121
+
122
+ var availablePhysicalMemory = new PerformanceCounter ( "Mono Memory" , "Available Physical Memory" ) ; //mono 4.0+
123
+ info . AvailablePhysicalMemory = Convert . ToInt64 ( availablePhysicalMemory . RawValue ) ;
124
+ }
125
+ } else {
126
+ var computerInfo = new Microsoft . VisualBasic . Devices . ComputerInfo ( ) ;
127
+ info . TotalPhysicalMemory = Convert . ToInt64 ( computerInfo . TotalPhysicalMemory ) ;
128
+ info . AvailablePhysicalMemory = Convert . ToInt64 ( computerInfo . AvailablePhysicalMemory ) ;
129
+ }
130
+ } catch ( Exception ex ) {
131
+ _log . FormattedInfo ( typeof ( EnvironmentInfoCollector ) , "Unable to get physical memory. Error message: {0}" , ex . Message ) ;
132
+ }
133
+ #endif
134
+ }
135
+
136
+ #if NET45
137
+ private bool IsMonoRuntime {
138
+ get {
139
+ try {
140
+ return Type . GetType ( "Mono.Runtime" ) != null ;
141
+ } catch ( Exception ) {
142
+ return false ;
143
+ }
144
+ }
145
+ }
146
+ #endif
147
+
148
+ private void PopulateRuntimeInfo ( EnvironmentInfo info ) {
149
+ try {
150
+ #if NET45 || NETSTANDARD1_5
151
+ info . MachineName = Environment . MachineName ;
152
+ #elif ! PORTABLE && ! NETSTANDARD1_2
153
+ Process process = Process . GetCurrentProcess ( ) ;
154
+ info . MachineName = process . MachineName ;
155
+ #else
156
+ info . MachineName = Guid . NewGuid ( ) . ToString ( "N" ) ;
157
+ #endif
158
+ } catch ( Exception ex ) {
159
+ _log . FormattedInfo ( typeof ( EnvironmentInfoCollector ) , "Unable to get machine name. Error message: {0}" , ex . Message ) ;
160
+ }
161
+
162
+ #if ! PORTABLE && ! NETSTANDARD1_2
163
+ #if NETSTANDARD
164
+ Microsoft . Extensions . PlatformAbstractions . PlatformServices computerInfo = null ;
165
+ #elif NET45
166
+ Microsoft . VisualBasic . Devices . ComputerInfo computerInfo = null ;
167
+ #endif
168
+
169
+ try {
170
+ #if NETSTANDARD
171
+ computerInfo = Microsoft . Extensions . PlatformAbstractions . PlatformServices . Default ;
172
+ #elif NET45
173
+ computerInfo = new Microsoft . VisualBasic . Devices . ComputerInfo ( ) ;
174
+ #endif
175
+ } catch ( Exception ex ) {
176
+ _log . FormattedInfo ( typeof ( EnvironmentInfoCollector ) , "Unable to get computer info. Error message: {0}" , ex . Message ) ;
177
+ }
178
+
179
+ #if NETSTANDARD || NET45
180
+ if ( computerInfo == null )
181
+ return ;
182
+ #endif
183
+
184
+ try {
185
+ #if NETSTANDARD
186
+ info . Data [ "ApplicationBasePath" ] = computerInfo . Application . ApplicationBasePath ;
187
+ info . Data [ "ApplicationName" ] = computerInfo . Application . ApplicationName ;
188
+ info . Data [ "RuntimeFramework" ] = computerInfo . Application . RuntimeFramework . FullName ;
189
+
190
+ info . OSName = computerInfo . Runtime . OperatingSystem ;
191
+ info . OSVersion = computerInfo . Runtime . OperatingSystemVersion ;
192
+ info . Architecture = computerInfo . Runtime . RuntimeArchitecture ;
193
+ info . RuntimeVersion = computerInfo . Runtime . RuntimeVersion ;
194
+ info . Data [ "RuntimeType" ] = computerInfo . Runtime . RuntimeType ; // Mono, CLR, CoreCLR
195
+ #elif NET45
196
+ info . OSName = computerInfo . OSFullName ;
197
+ info . OSVersion = computerInfo . OSVersion ;
198
+ info . Architecture = Is64BitOperatingSystem ( ) ? "x64" : "x86" ;
199
+ info . RuntimeVersion = Environment . Version . ToString ( ) ;
200
+ #endif
201
+ } catch ( Exception ex ) {
202
+ _log . FormattedInfo ( typeof ( EnvironmentInfoCollector ) , "Unable to get populate runtime info. Error message: {0}" , ex . Message ) ;
203
+ }
204
+ #endif
205
+ }
206
+
207
+ #if NET45
208
+ private bool Is64BitOperatingSystem ( ) {
209
+ if ( IntPtr . Size == 8 ) // 64-bit programs run only on Win64
210
+ return true ;
211
+
212
+ try {
213
+ // Detect whether the current process is a 32-bit process running on a 64-bit system.
214
+ bool is64 ;
215
+ bool methodExist = KernelNativeMethods . MethodExists ( "kernel32.dll" , "IsWow64Process" ) ;
216
+
217
+ return ( ( methodExist && KernelNativeMethods . IsWow64Process ( KernelNativeMethods . GetCurrentProcess ( ) , out is64 ) ) && is64 ) ;
218
+ } catch ( Exception ex ) {
219
+ _log . FormattedInfo ( typeof ( EnvironmentInfoCollector ) , "Unable to get CPU architecture. Error message: {0}" , ex . Message ) ;
220
+ }
221
+
222
+ return false ;
223
+ }
224
+
225
+ private static class KernelNativeMethods {
226
+ #region Kernel32
227
+
228
+ [ DllImport ( "kernel32" , CharSet = CharSet . Unicode , SetLastError = true ) ]
229
+ public static extern IntPtr GetProcAddress ( IntPtr hModule , [ MarshalAs ( UnmanagedType . LPStr ) ] string procName ) ;
230
+
231
+ [ DllImport ( "kernel32.dll" , CharSet = CharSet . Unicode , SetLastError = true ) ]
232
+ [ return : MarshalAs ( UnmanagedType . Bool ) ]
233
+ public static extern bool IsWow64Process ( IntPtr hProcess , out bool wow64Process ) ;
234
+
235
+ [ DllImport ( "kernel32.dll" ) ]
236
+ public static extern IntPtr GetCurrentProcess ( ) ;
237
+
238
+ [ DllImport ( "kernel32.dll" ) ]
239
+ public static extern int GetCurrentProcessId ( ) ;
240
+
241
+ [ DllImport ( "kernel32.dll" , CharSet = CharSet . Unicode , SetLastError = true ) ]
242
+ [ PreserveSig ]
243
+ public static extern int GetModuleFileName ( [ In ] IntPtr hModule , [ Out ] StringBuilder lpFilename , [ In ] [ MarshalAs ( UnmanagedType . U4 ) ] int nSize ) ;
244
+
245
+ [ DllImport ( "kernel32.dll" , CharSet = CharSet . Unicode ) ]
246
+ public static extern IntPtr GetModuleHandle ( string moduleName ) ;
247
+
248
+ [ DllImport ( "kernel32.dll" ) ]
249
+ public static extern int GetCurrentThreadId ( ) ;
250
+
251
+ #endregion
252
+
253
+ public static bool MethodExists ( string moduleName , string methodName ) {
254
+ IntPtr moduleHandle = GetModuleHandle ( moduleName ) ;
255
+ if ( moduleHandle == IntPtr . Zero )
256
+ return false ;
257
+
258
+ return ( GetProcAddress ( moduleHandle , methodName ) != IntPtr . Zero ) ;
259
+ }
260
+ }
261
+ #endif
16
262
}
17
- }
263
+ }
0 commit comments