PageRenderTime 39ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/WCFWebApi/src/Microsoft.Server.Common/Microsoft/Server/Common/Diagnostics/DiagnosticEventProvider.cs

#
C# | 883 lines | 676 code | 73 blank | 134 comment | 149 complexity | aaed747b6a03d0f41415c779f1b6d62d MD5 | raw file
Possible License(s): CC-BY-SA-3.0, Apache-2.0
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //-----------------------------------------------------------------------------
  4. namespace Microsoft.Server.Common.Diagnostics
  5. {
  6. using System;
  7. using System.Diagnostics.CodeAnalysis;
  8. using System.Globalization;
  9. using System.Runtime.InteropServices;
  10. using System.Security;
  11. using System.Security.Permissions;
  12. using System.Threading;
  13. using Microsoft.Server.Common.Interop;
  14. // This is a class defined based on CLR's internal implementation of ETW provider
  15. // This class should be replaced with CLR's version (whenever avaialble) that exposes callback functionality
  16. [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
  17. public class DiagnosticsEventProvider : IDisposable
  18. {
  19. [SecurityCritical]
  20. [Fx.Tag.SecurityNote(Critical = "Calling Unsafe code; usage of UnsafeNativeMethods.EtwEnableCallback")]
  21. UnsafeNativeMethods.EtwEnableCallback etwCallback; // Trace Callback function
  22. long traceRegistrationHandle; // Trace Registration Handle
  23. byte currentTraceLevel; // Tracing Level
  24. long anyKeywordMask; // Trace Enable Flags
  25. long allKeywordMask; // Match all keyword
  26. bool isProviderEnabled; // Enabled flag from Trace callback
  27. Guid providerId; // Control Guid
  28. int isDisposed; // when 1, provider has unregister
  29. [ThreadStatic]
  30. static WriteEventErrorCode errorCode; // The last return code stored from a WriteEvent call
  31. const int basicTypeAllocationBufferSize = 16;
  32. const int etwMaxNumberArguments = 32;
  33. const int etwAPIMaxStringCount = 8;
  34. const int maxEventDataDescriptors = 128;
  35. const int traceEventMaximumSize = 65482;
  36. const int traceEventMaximumStringSize = 32724;
  37. const int WindowsVistaMajorNumber = 6;
  38. [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")]
  39. public enum WriteEventErrorCode : int
  40. {
  41. NoError,
  42. NoFreeBuffers,
  43. EventTooBig
  44. }
  45. /// <summary>
  46. /// Constructs a new EventProvider. This causes the class to be registered with the OS
  47. /// if an ETW controller turns on the logging then logging will start.
  48. /// </summary>
  49. /// <param name="providerGuid">The GUID that identifies this provider to the system.</param>
  50. [SecurityCritical]
  51. [PermissionSet(SecurityAction.Demand, Unrestricted = true)]
  52. [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", Justification = "Use of guid here is acceptable.")]
  53. protected DiagnosticsEventProvider(Guid providerGuid)
  54. {
  55. this.providerId = providerGuid;
  56. EtwRegister();
  57. }
  58. /// <summary>
  59. /// This method registers the controlGuid of this class with ETW.
  60. /// We need to be running on Vista or above. If not a
  61. /// PlatformNotSupported exception will be thrown.
  62. /// If for some reason the ETW EtwRegister call failed
  63. /// a NotSupported exception will be thrown.
  64. /// </summary>
  65. [SecurityCritical]
  66. [SuppressMessage("Reliability", "Reliability102:WrapExceptionsRule",
  67. Justification = "Don't trace exceptions thrown from the initialization API.")]
  68. unsafe void EtwRegister()
  69. {
  70. this.etwCallback = new UnsafeNativeMethods.EtwEnableCallback(EtwEnableCallBack);
  71. uint etwRegistrationStatus = UnsafeNativeMethods.EventRegister(ref this.providerId, this.etwCallback, null, ref this.traceRegistrationHandle);
  72. if (etwRegistrationStatus != 0)
  73. {
  74. throw new InvalidOperationException(SR.EtwRegistrationFailed(etwRegistrationStatus.ToString("x", CultureInfo.CurrentCulture)));
  75. }
  76. }
  77. //
  78. // implement Dispose Pattern to early deregister from ETW instead of waiting for
  79. // the finalizer to call deregistration.
  80. // Once the user is done with the provider it needs to call Close() or Dispose()
  81. // If neither are called the finalizer will unregister the provider anyway
  82. //
  83. public void Dispose()
  84. {
  85. Dispose(true);
  86. GC.SuppressFinalize(this);
  87. }
  88. [System.Security.SecuritySafeCritical]
  89. protected virtual void Dispose(bool disposing)
  90. {
  91. if ((this.isDisposed != 1) && (Interlocked.Exchange(ref this.isDisposed, 1) == 0))
  92. {
  93. this.isProviderEnabled = false;
  94. Deregister();
  95. }
  96. }
  97. /// <summary>
  98. /// This method deregisters the controlGuid of this class with ETW.
  99. /// </summary>
  100. public virtual void Close()
  101. {
  102. Dispose();
  103. }
  104. ~DiagnosticsEventProvider()
  105. {
  106. Dispose(false);
  107. }
  108. /// <summary>
  109. /// This method un-registers from ETW.
  110. /// </summary>
  111. [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults")]
  112. [SecurityCritical]
  113. unsafe void Deregister()
  114. {
  115. // Unregister from ETW using the RegHandle saved from
  116. // the register call.
  117. if (this.traceRegistrationHandle != 0)
  118. {
  119. UnsafeNativeMethods.EventUnregister(this.traceRegistrationHandle);
  120. this.traceRegistrationHandle = 0;
  121. }
  122. }
  123. [SecurityCritical]
  124. unsafe void EtwEnableCallBack(
  125. [In] ref System.Guid sourceId,
  126. [In] int isEnabled,
  127. [In] byte setLevel,
  128. [In] long anyKeyword,
  129. [In] long allKeyword,
  130. [In] void* filterData,
  131. [In] void* callbackContext
  132. )
  133. {
  134. this.isProviderEnabled = (isEnabled != 0);
  135. this.currentTraceLevel = setLevel;
  136. this.anyKeywordMask = anyKeyword;
  137. this.allKeywordMask = allKeyword;
  138. OnControllerCommand();
  139. }
  140. protected virtual void OnControllerCommand() { }
  141. /// <summary>
  142. /// IsEnabled, method used to test if provider is enabled
  143. /// </summary>
  144. public bool IsEnabled()
  145. {
  146. return this.isProviderEnabled;
  147. }
  148. /// <summary>
  149. /// IsEnabled, method used to test if event is enabled
  150. /// </summary>
  151. /// <param name="level">
  152. /// Level to test
  153. /// </param>
  154. /// <param name="keywords">
  155. /// Keyword to test
  156. /// </param>
  157. public bool IsEnabled(byte level, long keywords)
  158. {
  159. if (this.isProviderEnabled)
  160. {
  161. if ((level <= this.currentTraceLevel) ||
  162. (this.currentTraceLevel == 0)) // This also covers the case of Level == 0.
  163. {
  164. // Check if Keyword is enabled
  165. if ((keywords == 0) ||
  166. (((keywords & this.anyKeywordMask) != 0) &&
  167. ((keywords & this.allKeywordMask) == this.allKeywordMask)))
  168. {
  169. return true;
  170. }
  171. }
  172. }
  173. return false;
  174. }
  175. [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
  176. public static WriteEventErrorCode GetLastWriteEventError()
  177. {
  178. return errorCode;
  179. }
  180. //
  181. // Helper function to set the last error on the thread
  182. //
  183. static void SetLastError(int error)
  184. {
  185. switch (error)
  186. {
  187. case UnsafeNativeMethods.ERROR_ARITHMETIC_OVERFLOW:
  188. case UnsafeNativeMethods.ERROR_MORE_DATA:
  189. errorCode = WriteEventErrorCode.EventTooBig;
  190. break;
  191. case UnsafeNativeMethods.ERROR_NOT_ENOUGH_MEMORY:
  192. errorCode = WriteEventErrorCode.NoFreeBuffers;
  193. break;
  194. }
  195. }
  196. /// <summary>
  197. /// This routine is used by WriteEvent to unbox the object type and
  198. /// to fill the passed in ETW data descriptor.
  199. /// </summary>
  200. /// <param name="data">argument to be decoded</param>
  201. /// <param name="dataDescriptor">pointer to the descriptor to be filled</param>
  202. /// <param name="dataBuffer">storage buffer for storing user data, needed because cant get the address of the object</param>
  203. /// <returns>null if the object is a basic type other than string. String otherwise</returns>
  204. [SecurityCritical]
  205. static unsafe string EncodeObject(ref object data, UnsafeNativeMethods.EventData* dataDescriptor, byte* dataBuffer)
  206. {
  207. dataDescriptor->Reserved = 0;
  208. string sRet = data as string;
  209. if (sRet != null)
  210. {
  211. dataDescriptor->Size = (uint)((sRet.Length + 1) * 2);
  212. return sRet;
  213. }
  214. if (data is IntPtr)
  215. {
  216. dataDescriptor->Size = (uint)sizeof(IntPtr);
  217. IntPtr* intptrPtr = (IntPtr*)dataBuffer;
  218. *intptrPtr = (IntPtr)data;
  219. dataDescriptor->DataPointer = (ulong)intptrPtr;
  220. }
  221. else if (data is int)
  222. {
  223. dataDescriptor->Size = (uint)sizeof(int);
  224. int* intptrPtr = (int*)dataBuffer;
  225. *intptrPtr = (int)data;
  226. dataDescriptor->DataPointer = (ulong)intptrPtr;
  227. }
  228. else if (data is long)
  229. {
  230. dataDescriptor->Size = (uint)sizeof(long);
  231. long* longptr = (long*)dataBuffer;
  232. *longptr = (long)data;
  233. dataDescriptor->DataPointer = (ulong)longptr;
  234. }
  235. else if (data is uint)
  236. {
  237. dataDescriptor->Size = (uint)sizeof(uint);
  238. uint* uintptr = (uint*)dataBuffer;
  239. *uintptr = (uint)data;
  240. dataDescriptor->DataPointer = (ulong)uintptr;
  241. }
  242. else if (data is UInt64)
  243. {
  244. dataDescriptor->Size = (uint)sizeof(ulong);
  245. UInt64* ulongptr = (ulong*)dataBuffer;
  246. *ulongptr = (ulong)data;
  247. dataDescriptor->DataPointer = (ulong)ulongptr;
  248. }
  249. else if (data is char)
  250. {
  251. dataDescriptor->Size = (uint)sizeof(char);
  252. char* charptr = (char*)dataBuffer;
  253. *charptr = (char)data;
  254. dataDescriptor->DataPointer = (ulong)charptr;
  255. }
  256. else if (data is byte)
  257. {
  258. dataDescriptor->Size = (uint)sizeof(byte);
  259. byte* byteptr = (byte*)dataBuffer;
  260. *byteptr = (byte)data;
  261. dataDescriptor->DataPointer = (ulong)byteptr;
  262. }
  263. else if (data is short)
  264. {
  265. dataDescriptor->Size = (uint)sizeof(short);
  266. short* shortptr = (short*)dataBuffer;
  267. *shortptr = (short)data;
  268. dataDescriptor->DataPointer = (ulong)shortptr;
  269. }
  270. else if (data is sbyte)
  271. {
  272. dataDescriptor->Size = (uint)sizeof(sbyte);
  273. sbyte* sbyteptr = (sbyte*)dataBuffer;
  274. *sbyteptr = (sbyte)data;
  275. dataDescriptor->DataPointer = (ulong)sbyteptr;
  276. }
  277. else if (data is ushort)
  278. {
  279. dataDescriptor->Size = (uint)sizeof(ushort);
  280. ushort* ushortptr = (ushort*)dataBuffer;
  281. *ushortptr = (ushort)data;
  282. dataDescriptor->DataPointer = (ulong)ushortptr;
  283. }
  284. else if (data is float)
  285. {
  286. dataDescriptor->Size = (uint)sizeof(float);
  287. float* floatptr = (float*)dataBuffer;
  288. *floatptr = (float)data;
  289. dataDescriptor->DataPointer = (ulong)floatptr;
  290. }
  291. else if (data is double)
  292. {
  293. dataDescriptor->Size = (uint)sizeof(double);
  294. double* doubleptr = (double*)dataBuffer;
  295. *doubleptr = (double)data;
  296. dataDescriptor->DataPointer = (ulong)doubleptr;
  297. }
  298. else if (data is bool)
  299. {
  300. dataDescriptor->Size = (uint)sizeof(bool);
  301. bool* boolptr = (bool*)dataBuffer;
  302. *boolptr = (bool)data;
  303. dataDescriptor->DataPointer = (ulong)boolptr;
  304. }
  305. else if (data is Guid)
  306. {
  307. dataDescriptor->Size = (uint)sizeof(Guid);
  308. Guid* guidptr = (Guid*)dataBuffer;
  309. *guidptr = (Guid)data;
  310. dataDescriptor->DataPointer = (ulong)guidptr;
  311. }
  312. else if (data is decimal)
  313. {
  314. dataDescriptor->Size = (uint)sizeof(decimal);
  315. decimal* decimalptr = (decimal*)dataBuffer;
  316. *decimalptr = (decimal)data;
  317. dataDescriptor->DataPointer = (ulong)decimalptr;
  318. }
  319. else if (data is Boolean)
  320. {
  321. dataDescriptor->Size = (uint)sizeof(Boolean);
  322. Boolean* booleanptr = (Boolean*)dataBuffer;
  323. *booleanptr = (Boolean)data;
  324. dataDescriptor->DataPointer = (ulong)booleanptr;
  325. }
  326. else
  327. {
  328. // Everything else is a just a string
  329. sRet = data.ToString();
  330. dataDescriptor->Size = (uint)((sRet.Length + 1) * 2);
  331. return sRet;
  332. }
  333. return null;
  334. }
  335. /// <summary>
  336. /// WriteMessageEvent, method to write a string with level and Keyword
  337. /// </summary>
  338. /// <param name="level">
  339. /// Level to test
  340. /// </param>
  341. /// <param name="Keyword">
  342. /// Keyword to test
  343. /// </param>
  344. [Fx.Tag.SecurityNote(Critical = "Calling Unsafe code; usage of EventDescriptor, which is protected by a LinkDemand")]
  345. [SecurityCritical]
  346. public bool WriteMessageEvent(EventTraceActivity eventTraceActivity, string eventMessage, byte eventLevel, long eventKeywords)
  347. {
  348. int status = 0;
  349. if (eventMessage == null)
  350. {
  351. throw Fx.Exception.AsError(new ArgumentNullException("eventMessage"));
  352. }
  353. if (eventTraceActivity != null)
  354. {
  355. SetActivityId(ref eventTraceActivity.ActivityId);
  356. }
  357. if (IsEnabled(eventLevel, eventKeywords))
  358. {
  359. if (eventMessage.Length > traceEventMaximumStringSize)
  360. {
  361. errorCode = WriteEventErrorCode.EventTooBig;
  362. return false;
  363. }
  364. unsafe
  365. {
  366. fixed (char* pdata = eventMessage)
  367. {
  368. status = (int)UnsafeNativeMethods.EventWriteString(this.traceRegistrationHandle, eventLevel, eventKeywords, pdata);
  369. }
  370. if (status != 0)
  371. {
  372. SetLastError(status);
  373. return false;
  374. }
  375. }
  376. }
  377. return true;
  378. }
  379. /// <summary>
  380. /// WriteMessageEvent, method to write a string with level=0 and Keyword=0
  381. /// </summary>
  382. /// <param name="eventMessage">
  383. /// Message to log
  384. /// </param>
  385. [SecurityCritical]
  386. [Fx.Tag.SecurityNote(Critical = "Accesses security critical code WriteMessageEvent")]
  387. public bool WriteMessageEvent(EventTraceActivity eventTraceActivity, string eventMessage)
  388. {
  389. return WriteMessageEvent(eventTraceActivity, eventMessage, 0, 0);
  390. }
  391. /// <summary>
  392. /// WriteEvent, method to write a parameters with event schema properties
  393. /// </summary>
  394. /// <param name="EventDescriptor">
  395. /// Event Descriptor for this event.
  396. /// </param>
  397. [SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", Justification = "Existing API")]
  398. [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "Ported from WCF")]
  399. [Fx.Tag.SecurityNote(Critical = "Calling Unsafe code; usage of EventDescriptor, which is protected by a LinkDemand")]
  400. [SecurityCritical]
  401. public bool WriteEvent(ref EventDescriptor eventDescriptor, EventTraceActivity eventTraceActivity, params object[] eventPayload)
  402. {
  403. uint status = 0;
  404. if (IsEnabled(eventDescriptor.Level, eventDescriptor.Keywords))
  405. {
  406. int argCount = 0;
  407. if (eventTraceActivity != null)
  408. {
  409. SetActivityId(ref eventTraceActivity.ActivityId);
  410. }
  411. unsafe
  412. {
  413. if ((eventPayload == null)
  414. || (eventPayload.Length == 0)
  415. || (eventPayload.Length == 1))
  416. {
  417. string dataString = null;
  418. UnsafeNativeMethods.EventData userData;
  419. byte* dataBuffer = stackalloc byte[basicTypeAllocationBufferSize]; // Assume a max of 16 chars for non-string argument
  420. userData.Size = 0;
  421. if ((eventPayload != null) && (eventPayload.Length != 0))
  422. {
  423. //
  424. // Figure out the type and fill the data descriptor
  425. //
  426. dataString = EncodeObject(ref eventPayload[0], &userData, dataBuffer);
  427. argCount = 1;
  428. }
  429. if (userData.Size > traceEventMaximumSize)
  430. {
  431. //
  432. // Maximum size of the event payload plus header is 64k
  433. //
  434. errorCode = WriteEventErrorCode.EventTooBig;
  435. return false;
  436. }
  437. if (dataString != null)
  438. {
  439. fixed (char* pdata = dataString)
  440. {
  441. userData.DataPointer = (ulong)pdata;
  442. status = UnsafeNativeMethods.EventWrite(this.traceRegistrationHandle, ref eventDescriptor, (uint)argCount, &userData);
  443. }
  444. }
  445. else
  446. {
  447. if (argCount == 0)
  448. {
  449. status = UnsafeNativeMethods.EventWrite(this.traceRegistrationHandle, ref eventDescriptor, 0, null);
  450. }
  451. else
  452. {
  453. status = UnsafeNativeMethods.EventWrite(this.traceRegistrationHandle, ref eventDescriptor, (uint)argCount, &userData);
  454. }
  455. }
  456. }
  457. else
  458. {
  459. argCount = eventPayload.Length;
  460. if (argCount > etwMaxNumberArguments)
  461. {
  462. //
  463. //too many arguments to log
  464. //
  465. throw Fx.Exception.AsError(new ArgumentOutOfRangeException("eventPayload",
  466. SR.EtwMaxNumberArgumentsExceeded(etwMaxNumberArguments)));
  467. }
  468. uint totalEventSize = 0;
  469. int index;
  470. int stringIndex = 0;
  471. int[] stringPosition = new int[etwAPIMaxStringCount];
  472. string[] dataString = new string[etwAPIMaxStringCount];
  473. UnsafeNativeMethods.EventData* userData = stackalloc UnsafeNativeMethods.EventData[argCount];
  474. UnsafeNativeMethods.EventData* userDataPtr = (UnsafeNativeMethods.EventData*)userData;
  475. byte* dataBuffer = stackalloc byte[basicTypeAllocationBufferSize * argCount]; // Assume 16 chars for non-string argument
  476. byte* currentBuffer = dataBuffer;
  477. //
  478. // The loop below goes through all the arguments and fills in the data
  479. // descriptors. For strings save the location in the dataString array.
  480. // Caculates the total size of the event by adding the data descriptor
  481. // size value set in EncodeObjec method.
  482. //
  483. for (index = 0; index < eventPayload.Length; index++)
  484. {
  485. if (eventPayload[index] != null)
  486. {
  487. string isString;
  488. isString = EncodeObject(ref eventPayload[index], userDataPtr, currentBuffer);
  489. currentBuffer += basicTypeAllocationBufferSize;
  490. totalEventSize += userDataPtr->Size;
  491. userDataPtr++;
  492. if (isString != null)
  493. {
  494. if (stringIndex < etwAPIMaxStringCount)
  495. {
  496. dataString[stringIndex] = isString;
  497. stringPosition[stringIndex] = index;
  498. stringIndex++;
  499. }
  500. else
  501. {
  502. throw Fx.Exception.AsError(new ArgumentOutOfRangeException("eventPayload",
  503. SR.EtwAPIMaxStringCountExceeded(etwAPIMaxStringCount)));
  504. }
  505. }
  506. }
  507. }
  508. if (totalEventSize > traceEventMaximumSize)
  509. {
  510. errorCode = WriteEventErrorCode.EventTooBig;
  511. return false;
  512. }
  513. //
  514. // now fix any string arguments and set the pointer on the data descriptor
  515. //
  516. fixed (char* v0 = dataString[0], v1 = dataString[1], v2 = dataString[2], v3 = dataString[3],
  517. v4 = dataString[4], v5 = dataString[5], v6 = dataString[6], v7 = dataString[7])
  518. {
  519. userDataPtr = (UnsafeNativeMethods.EventData*)userData;
  520. if (dataString[0] != null)
  521. {
  522. userDataPtr[stringPosition[0]].DataPointer = (ulong)v0;
  523. }
  524. if (dataString[1] != null)
  525. {
  526. userDataPtr[stringPosition[1]].DataPointer = (ulong)v1;
  527. }
  528. if (dataString[2] != null)
  529. {
  530. userDataPtr[stringPosition[2]].DataPointer = (ulong)v2;
  531. }
  532. if (dataString[3] != null)
  533. {
  534. userDataPtr[stringPosition[3]].DataPointer = (ulong)v3;
  535. }
  536. if (dataString[4] != null)
  537. {
  538. userDataPtr[stringPosition[4]].DataPointer = (ulong)v4;
  539. }
  540. if (dataString[5] != null)
  541. {
  542. userDataPtr[stringPosition[5]].DataPointer = (ulong)v5;
  543. }
  544. if (dataString[6] != null)
  545. {
  546. userDataPtr[stringPosition[6]].DataPointer = (ulong)v6;
  547. }
  548. if (dataString[7] != null)
  549. {
  550. userDataPtr[stringPosition[7]].DataPointer = (ulong)v7;
  551. }
  552. status = UnsafeNativeMethods.EventWrite(this.traceRegistrationHandle, ref eventDescriptor, (uint)argCount, userData);
  553. }
  554. }
  555. }
  556. }
  557. if (status != 0)
  558. {
  559. SetLastError((int)status);
  560. return false;
  561. }
  562. return true;
  563. }
  564. /// <summary>
  565. /// WriteEvent, method to write a string with event schema properties
  566. /// </summary>
  567. /// <param name="EventDescriptor">
  568. /// Event Descriptor for this event.
  569. /// </param>
  570. /// <param name="data">
  571. /// string to log.
  572. /// </param>
  573. [SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", Justification = "Existing API")]
  574. [Fx.Tag.SecurityNote(Critical = "Calling Unsafe code; usage of EventDescriptor, which is protected by a LinkDemand")]
  575. [SecurityCritical]
  576. public bool WriteEvent(ref EventDescriptor eventDescriptor, EventTraceActivity eventTraceActivity, string data)
  577. {
  578. uint status = 0;
  579. //check all strings for null
  580. data = (data ?? string.Empty);
  581. if (IsEnabled(eventDescriptor.Level, eventDescriptor.Keywords))
  582. {
  583. if (data.Length > traceEventMaximumStringSize)
  584. {
  585. errorCode = WriteEventErrorCode.EventTooBig;
  586. return false;
  587. }
  588. if (eventTraceActivity != null)
  589. {
  590. SetActivityId(ref eventTraceActivity.ActivityId);
  591. }
  592. UnsafeNativeMethods.EventData userData;
  593. userData.Size = (uint)((data.Length + 1) * 2);
  594. userData.Reserved = 0;
  595. unsafe
  596. {
  597. fixed (char* pdata = data)
  598. {
  599. userData.DataPointer = (ulong)pdata;
  600. status = UnsafeNativeMethods.EventWrite(this.traceRegistrationHandle, ref eventDescriptor, 1, &userData);
  601. }
  602. }
  603. }
  604. if (status != 0)
  605. {
  606. SetLastError((int)status);
  607. return false;
  608. }
  609. return true;
  610. }
  611. /// <summary>
  612. /// WriteEvent, method to be used by generated code on a derived class
  613. /// </summary>
  614. /// <param name="EventDescriptor">
  615. /// Event Descriptor for this event.
  616. /// </param>
  617. /// <param name="count">
  618. /// number of event descriptors
  619. /// </param>
  620. /// <param name="data">
  621. /// pointer do the event data
  622. /// </param>
  623. [SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", Justification = "Existing API")]
  624. [Fx.Tag.SecurityNote(Critical = "Calling Unsafe code; usage of EventDescriptor, which is protected by a LinkDemand")]
  625. [SecurityCritical]
  626. internal protected bool WriteEvent(ref EventDescriptor eventDescriptor, EventTraceActivity eventTraceActivity, int dataCount, IntPtr data)
  627. {
  628. uint status = 0;
  629. if (eventTraceActivity != null)
  630. {
  631. SetActivityId(ref eventTraceActivity.ActivityId);
  632. }
  633. unsafe
  634. {
  635. status = UnsafeNativeMethods.EventWrite(this.traceRegistrationHandle, ref eventDescriptor, (uint)dataCount, (UnsafeNativeMethods.EventData*)data);
  636. }
  637. if (status != 0)
  638. {
  639. SetLastError((int)status);
  640. return false;
  641. }
  642. return true;
  643. }
  644. /// <summary>
  645. /// WriteTransferEvent, method to write a parameters with event schema properties
  646. /// </summary>
  647. /// <param name="eventDescriptor">
  648. /// Event Descriptor for this event.
  649. /// </param>
  650. [SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", Justification = "Existing API")]
  651. [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "Ported from WCF")]
  652. [Fx.Tag.SecurityNote(Critical = "Calling Unsafe code; usage of EventDescriptor, which is protected by a LinkDemand")]
  653. [SecurityCritical]
  654. public bool WriteTransferEvent(ref EventDescriptor eventDescriptor, EventTraceActivity eventTraceActivity, Guid relatedActivityId, params object[] eventPayload)
  655. {
  656. // ActivityId is required when writing transfer event
  657. if (eventTraceActivity == null)
  658. {
  659. Fx.Assert(false, "eventTraceActivity should not be null for WriteTransferEvent");
  660. eventTraceActivity = EventTraceActivity.Empty;
  661. }
  662. uint status = 0;
  663. if (IsEnabled(eventDescriptor.Level, eventDescriptor.Keywords))
  664. {
  665. unsafe
  666. {
  667. if ((eventPayload != null) && (eventPayload.Length != 0))
  668. {
  669. int argCount = eventPayload.Length;
  670. if (argCount > etwMaxNumberArguments)
  671. {
  672. //
  673. //too many arguments to log
  674. //
  675. throw Fx.Exception.AsError(new ArgumentOutOfRangeException("eventPayload",
  676. SR.EtwMaxNumberArgumentsExceeded(etwMaxNumberArguments)));
  677. }
  678. uint totalEventSize = 0;
  679. int index;
  680. int stringIndex = 0;
  681. int[] stringPosition = new int[etwAPIMaxStringCount]; //used to keep the position of strings in the eventPayload parameter
  682. string[] dataString = new string[etwAPIMaxStringCount]; // string arrays from the eventPayload parameter
  683. UnsafeNativeMethods.EventData* userData = stackalloc UnsafeNativeMethods.EventData[argCount]; // allocation for the data descriptors
  684. UnsafeNativeMethods.EventData* userDataPtr = (UnsafeNativeMethods.EventData*)userData;
  685. byte* dataBuffer = stackalloc byte[basicTypeAllocationBufferSize * argCount]; // 16 byte for unboxing non-string argument
  686. byte* currentBuffer = dataBuffer;
  687. //
  688. // The loop below goes through all the arguments and fills in the data
  689. // descriptors. For strings save the location in the dataString array.
  690. // Caculates the total size of the event by adding the data descriptor
  691. // size value set in EncodeObjec method.
  692. //
  693. for (index = 0; index < eventPayload.Length; index++)
  694. {
  695. if (eventPayload[index] != null)
  696. {
  697. string isString;
  698. isString = EncodeObject(ref eventPayload[index], userDataPtr, currentBuffer);
  699. currentBuffer += basicTypeAllocationBufferSize;
  700. totalEventSize += userDataPtr->Size;
  701. userDataPtr++;
  702. if (isString != null)
  703. {
  704. if (stringIndex < etwAPIMaxStringCount)
  705. {
  706. dataString[stringIndex] = isString;
  707. stringPosition[stringIndex] = index;
  708. stringIndex++;
  709. }
  710. else
  711. {
  712. throw Fx.Exception.AsError(new ArgumentOutOfRangeException("eventPayload",
  713. SR.EtwAPIMaxStringCountExceeded(etwAPIMaxStringCount)));
  714. }
  715. }
  716. }
  717. }
  718. if (totalEventSize > traceEventMaximumSize)
  719. {
  720. errorCode = WriteEventErrorCode.EventTooBig;
  721. return false;
  722. }
  723. fixed (char* v0 = dataString[0], v1 = dataString[1], v2 = dataString[2], v3 = dataString[3],
  724. v4 = dataString[4], v5 = dataString[5], v6 = dataString[6], v7 = dataString[7])
  725. {
  726. userDataPtr = (UnsafeNativeMethods.EventData*)userData;
  727. if (dataString[0] != null)
  728. {
  729. userDataPtr[stringPosition[0]].DataPointer = (ulong)v0;
  730. }
  731. if (dataString[1] != null)
  732. {
  733. userDataPtr[stringPosition[1]].DataPointer = (ulong)v1;
  734. }
  735. if (dataString[2] != null)
  736. {
  737. userDataPtr[stringPosition[2]].DataPointer = (ulong)v2;
  738. }
  739. if (dataString[3] != null)
  740. {
  741. userDataPtr[stringPosition[3]].DataPointer = (ulong)v3;
  742. }
  743. if (dataString[4] != null)
  744. {
  745. userDataPtr[stringPosition[4]].DataPointer = (ulong)v4;
  746. }
  747. if (dataString[5] != null)
  748. {
  749. userDataPtr[stringPosition[5]].DataPointer = (ulong)v5;
  750. }
  751. if (dataString[6] != null)
  752. {
  753. userDataPtr[stringPosition[6]].DataPointer = (ulong)v6;
  754. }
  755. if (dataString[7] != null)
  756. {
  757. userDataPtr[stringPosition[7]].DataPointer = (ulong)v7;
  758. }
  759. status = UnsafeNativeMethods.EventWriteTransfer(this.traceRegistrationHandle, ref eventDescriptor, ref eventTraceActivity.ActivityId, ref relatedActivityId, (uint)argCount, userData);
  760. }
  761. }
  762. else
  763. {
  764. status = UnsafeNativeMethods.EventWriteTransfer(this.traceRegistrationHandle, ref eventDescriptor, ref eventTraceActivity.ActivityId, ref relatedActivityId, 0, null);
  765. }
  766. }
  767. }
  768. if (status != 0)
  769. {
  770. SetLastError((int)status);
  771. return false;
  772. }
  773. return true;
  774. }
  775. [SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", Justification = "Existing API")]
  776. [SecurityCritical]
  777. [Fx.Tag.SecurityNote(Critical = "Calling Unsafe code; usage of EventDescriptor, which is protected by a LinkDemand")]
  778. protected bool WriteTransferEvent(ref EventDescriptor eventDescriptor, EventTraceActivity eventTraceActivity, Guid relatedActivityId, int dataCount, IntPtr data)
  779. {
  780. // ActivityId is required when writing transfer event
  781. if (eventTraceActivity == null)
  782. {
  783. throw Fx.Exception.ArgumentNull("eventTraceActivity");
  784. }
  785. uint status = 0;
  786. unsafe
  787. {
  788. status = UnsafeNativeMethods.EventWriteTransfer(this.traceRegistrationHandle,
  789. ref eventDescriptor,
  790. ref eventTraceActivity.ActivityId,
  791. ref relatedActivityId,
  792. (uint)dataCount,
  793. (UnsafeNativeMethods.EventData*)data);
  794. }
  795. if (status != 0)
  796. {
  797. SetLastError((int)status);
  798. return false;
  799. }
  800. return true;
  801. }
  802. [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", MessageId = "Microsoft.Server.Common.Interop.UnsafeNativeMethods.EventActivityIdControl(System.Int32,System.Guid@)", Justification = "Ported code from")]
  803. [SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", Justification = "Existing API")]
  804. [SecurityCritical]
  805. public static void SetActivityId(ref Guid id)
  806. {
  807. UnsafeNativeMethods.EventActivityIdControl((int)ActivityControl.EVENT_ACTIVITY_CTRL_SET_ID, ref id);
  808. }
  809. }
  810. }