public static int Run <T>(string[] args, DebuggerAttachPoints attachPoints, uint timeout = 30) where T : ModularInput, new() { if (!IsAttachPointNone(attachPoints) && timeout == 0) { throw new ArgumentOutOfRangeException("timeout", timeout, "Timeout parameter must be greater than or equal to 1 second"); } T script = new T(); Task <int> run = script.RunAsync(args, _stdin, _stdout, _stderr, null, attachPoints, timeout); run.Wait(); if (run.IsCompleted) { return(run.Result); } return(-1); }
internal static bool ShouldWaitForDebuggerToAttach(string[] args, DebuggerAttachPoints attachPoints) { if (IsAttachPointNone(attachPoints)) { return(false); } if (args.Length > 0) { if (IsValidateArguments(args, attachPoints)) { return(true); } } else if (IsStreamEvents(attachPoints)) { return(true); } return(false); }
/// <summary> /// Performs the action specified by the <paramref name="args"/> parameter. /// </summary> /// <param name="args"> /// Command-line arguments provided by Splunk when it invokes the /// modular input program. Implementers should pass the arguments to /// the main method of the program as the value of this parameter. /// </param> /// <returns> /// <param name="stdin"> /// Reader to use for the stdin stream /// </param> /// <param name="stdout"> /// Writer to use for the stdout stream /// </param> /// <param name="stderr"> /// Writer to use for the stderr stream /// </param> /// <param name="progress"> /// Reports back progress as events are written to the <see cref="EventWriter"/> /// </param> /// <param name="attachPoints"> /// Defines the <see cref="DebuggerAttachPoints"/> for this input /// </param> /// <param name="timeout"> /// Number of seconds to wait for a debugger to attach before continuing processing. /// </param> /// A value which should be used as the exit code from the modular /// input program. A value of <c>0</c> indicates success. A non-zero /// value indicates failure. /// </returns> /// <remarks> /// If the <paramref name="args"/> are not in the supported set of values, /// the method will do nothing and return a non-zero value. Any /// exceptions and internal progress messages encountered during /// execution are written to the splunkd log file. /// </remarks> public async Task <int> RunAsync(string[] args, TextReader stdin = null, TextWriter stdout = null, TextWriter stderr = null, IProgress <EventWrittenProgressReport> progress = null, DebuggerAttachPoints attachPoints = DebuggerAttachPoints.None, uint timeout = 0 ) { EventWriter writer = null; string name = this.GetType().FullName; try { /// Console default is OEM text encoding, which is not handled by Splunk, //// resulting in loss of chars such as O with an umlaut (\u0150) //// Splunk's default is UTF8. if (stdin == null) { stdin = Console.In; Console.InputEncoding = Encoding.UTF8; } if (stdout == null) { stdout = Console.Out; Console.OutputEncoding = Encoding.UTF8; } if (stderr == null) { stderr = Console.Error; Console.OutputEncoding = Encoding.UTF8; } if (progress == null) { progress = new Progress <EventWrittenProgressReport>(); } writer = new EventWriter(stdout, stderr, progress); // Check if the developer has specified they want to attach a debugger bool wait = ShouldWaitForDebuggerToAttach(args, attachPoints); // If a debugger is going to attach if (wait) { WaitForAttach(timeout); } if (args.Length == 0) { try { List <Task> instances = new List <Task>(); InputDefinitionCollection inputDefinitions = (InputDefinitionCollection) new XmlSerializer(typeof(InputDefinitionCollection)). Deserialize(stdin); foreach (InputDefinition inputDefinition in inputDefinitions) { var inputTask = this.StreamEventsAsync(inputDefinition, writer); instances.Add(inputTask); var inputName = inputDefinition.Name; inputTask.ContinueWith(t => { if (inputTask.Exception != null) { var message = RemoveNewLines(inputTask.Exception.InnerException.ToString()); writer.LogAsync(Severity.Fatal, string.Format("Exception during streaming: name={0} | {1}", inputName, message)) .Wait(); } }); } try { await Task.WhenAll(instances.ToArray()); } catch { } await writer.CompleteAsync(); } catch (Exception e) { var message = RemoveNewLines(e.ToString()); writer.LogAsync(Severity.Fatal, string.Format("Exception during streaming: name={0} | {1}", name, message)) .Wait(); return(-1); } return(0); } if (args[0].ToLower().Equals("--scheme")) { Scheme scheme = null; try { scheme = this.Scheme; if (scheme != null) { StringWriter stringWriter = new StringWriter(); new XmlSerializer(typeof(Scheme)).Serialize(stringWriter, scheme); stdout.WriteLine(stringWriter.ToString()); return(0); } throw new NullReferenceException("Scheme was null; could not serialize."); } catch (Exception e) { var message = RemoveNewLines(e.ToString()); writer.LogAsync(Severity.Fatal, string.Format("Exception getting scheme: name={0} | {1}", name, message)) .Wait(); return(-1); } finally { writer.CompleteAsync().Wait(); } } if (args[0].ToLower().Equals("--validate-arguments")) { string errorMessage = null; string inputDoc = null; try { inputDoc = await stdin.ReadToEndAsync(); inputDoc = RemoveNewLines(inputDoc); writer.LogAsync(Severity.Info, inputDoc).Wait(); Validation validation = (Validation) new XmlSerializer(typeof(Validation)). Deserialize(new StringReader(inputDoc)); name = validation.Name; bool validationSuccessful = true; Scheme scheme = this.Scheme; foreach (Argument arg in scheme.Arguments) { if (arg.ValidationDelegate != null) { if (!arg.ValidationDelegate(validation.Parameters[arg.Name], out errorMessage)) { validationSuccessful = false; break; } } } if (validationSuccessful && this.Validate(validation, out errorMessage)) { return(0); // Validation succeeded } } catch (Exception e) { var message = RemoveNewLines(e.ToString()); errorMessage = e.Message; writer.LogAsync(Severity.Fatal, string.Format("Exception during validation: name={0} | {1}", name, message)) .Wait(); } finally { writer.CompleteAsync().Wait(); } if (errorMessage != null) { using (var xmlWriter = XmlWriter.Create(stdout, new XmlWriterSettings { Async = true, ConformanceLevel = ConformanceLevel.Fragment })) { await xmlWriter.WriteStartElementAsync(prefix : null, localName : "error", ns : null); await xmlWriter.WriteElementStringAsync(prefix : null, localName : "message", ns : null, value : errorMessage); await xmlWriter.WriteEndElementAsync(); } } return(-1); } } catch (Exception e) { if (writer != null) { var message = RemoveNewLines(e.ToString()); writer.LogAsync(Severity.Error, string.Format("Exception during execution: name={0} | {1}", name, message)).Wait(); } } finally { if (writer != null) { writer.CompleteAsync().Wait(); } } await writer.LogAsync(Severity.Error, string.Format("Exception during execution: Invalid arguments: name={0}", name)); return(-1); }
private static bool IsValidateArguments(string[] args, DebuggerAttachPoints attachPoints) { return(args[0].ToLower().Equals("--validate-arguments") && ((attachPoints & DebuggerAttachPoints.ValidateArguments) == DebuggerAttachPoints.ValidateArguments)); }
private static bool IsStreamEvents(DebuggerAttachPoints attachPoints) { return((attachPoints & DebuggerAttachPoints.StreamEvents) == DebuggerAttachPoints.StreamEvents); }
private static bool IsAttachPointNone(DebuggerAttachPoints attachPoints) { return(attachPoints == DebuggerAttachPoints.None); }
/// <summary> /// Performs the action specified by the <paramref name="args"/> parameter. /// </summary> /// <param name="args"> /// Command-line arguments provided by Splunk when it invokes the /// modular input program. Implementers should pass the arguments to /// the main method of the program as the value of this parameter. /// </param> /// <returns> /// <param name="stdin"> /// Reader to use for the stdin stream /// </param> /// <param name="stdout"> /// Writer to use for the stdout stream /// </param> /// <param name="stderr"> /// Writer to use for the stderr stream /// </param> /// <param name="progress"> /// Reports back progress as events are written to the <see cref="EventWriter"/> /// </param> /// <param name="attachPoints"> /// Defines the <see cref="DebuggerAttachPoints"/> for this input /// </param> /// <param name="timeout"> /// Number of seconds to wait for a debugger to attach before continuing processing. /// </param> /// A value which should be used as the exit code from the modular /// input program. A value of <c>0</c> indicates success. A non-zero /// value indicates failure. /// </returns> /// <remarks> /// If the <paramref name="args"/> are not in the supported set of values, /// the method will do nothing and return a non-zero value. Any /// exceptions and internal progress messages encountered during /// execution are written to the splunkd log file. /// </remarks> public async Task <int> RunAsync(string[] args, TextReader stdin = null, TextWriter stdout = null, TextWriter stderr = null, IProgress <EventWrittenProgressReport> progress = null, DebuggerAttachPoints attachPoints = DebuggerAttachPoints.None, uint timeout = 0 ) { EventWriter writer = null; string name = this.GetType().FullName; try { /// Console default is OEM text encoding, which is not handled by Splunk, //// resulting in loss of chars such as O with an umlaut (\u0150) //// Splunk's default is UTF8. if (stdin == null) { stdin = Console.In; Console.InputEncoding = Encoding.UTF8; } if (stdout == null) { stdout = Console.Out; Console.OutputEncoding = Encoding.UTF8; } if (stderr == null) { stderr = Console.Error; Console.OutputEncoding = Encoding.UTF8; } if (progress == null) { progress = new Progress <EventWrittenProgressReport>(); } writer = new EventWriter(stdout, stderr, progress); // Check if the developer has specified they want to attach a debugger bool wait = ShouldWaitForDebuggerToAttach(args, attachPoints); // If a debugger is going to attach if (wait) { WaitForAttach(timeout); } if (args.Length == 0) { try { var serializer = new XmlSerializer(typeof(InputDefinitionCollection)); var inputDefinitions = (InputDefinitionCollection)serializer.Deserialize(stdin); var instances = new List <Task>(); foreach (InputDefinition inputDefinition in inputDefinitions) { var inputTask = this.StreamEventsAsync(inputDefinition, writer); instances.Add(inputTask); # pragma warning disable 4014 inputTask.ContinueWith(t => { if (inputTask.Exception != null) { var message = RemoveNewLines(inputTask.Exception.InnerException.ToString()); writer.LogAsync(Severity.Fatal, string.Format("Exception during streaming: name={0} | {1}", inputDefinition.Name, message)).Wait(); } }); # pragma warning restore 4014 } try { await Task.WhenAll(instances.ToArray()); } catch { } await writer.CompleteAsync(); } catch (Exception e) { var message = RemoveNewLines(e.ToString()); writer.LogAsync(Severity.Fatal, string.Format("Exception during streaming: name={0} | {1}", name, message)).Wait(); return(-1); } return(0); }