private void Runner() { CancellationTokenSource?.Dispose(); CancellationTokenSource = new CancellationTokenSource(); CancellationToken = CancellationTokenSource.Token; MessageDataItem message = null; while (true) { if (SpinWait.SpinUntil(() => AttachedQueue.TryTake(out message), 1)) { ProcessMessage(message); // assume there are more messages // NB! No need to test CancellationToken in this loop, because it's a kind of attempt to drain the queue. If not achieved in-time, // will be terminated forcibly. while (AttachedQueue.TryTake(out message)) { ProcessMessage(message); } } // no messages left if (CancellationToken.IsCancellationRequested) { break; } } // All done, but let's drain the queue -- if anything left it will never be completed while (AttachedQueue.Count > 0) { Thread.Sleep(5); } WorkCompleted.Set(); }
public bool Evaluate(MessageDataItem dataItem) { Variant firstValue = FirstValue.GetValue(dataItem); string message = null; switch (firstValue.Type) { case VariantType.Boolean: message = firstValue.BooleanValue.ToString(); break; case VariantType.DateTime: message = firstValue.DateTimeValue.ToString("o"); break; case VariantType.Float: message = firstValue.FloatValue.ToString(); break; case VariantType.Int: message = firstValue.IntValue.ToString(); break; case VariantType.String: message = firstValue.StringValue; break; } if (Operator == RegExExpressionOperator.Matches) { return(RegularExpressions.Evaluate(message)); } if (Operator == RegExExpressionOperator.NotMatches) { return(!RegularExpressions.Evaluate(message)); } return(false); }
protected void UDPWorkerProc() { try { EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); byte[] buffer = new byte[bufferSize]; while (true) { Task <SocketReceiveFromResult> udpAsyncResult = socket.ReceiveFromAsync(new ArraySegment <byte>(buffer), SocketFlags.None, remoteEndPoint); try { udpAsyncResult.Wait(token); } catch (OperationCanceledException) { break; } int bytesReceived = udpAsyncResult.Result.ReceivedBytes; if (bytesReceived > 0) { MessageDataItem message = CreateMessageDataItem(Encoding.ASCII.GetString(buffer, 0, bytesReceived).Trim(TrailerChars), udpAsyncResult.Result.RemoteEndPoint); MessageSender.Invoke(message, false); } } } finally { socket?.Close(); } }
protected void AddSyslogPRI(MessageDataItem message, int facility, int severity) { if (OutCode) { message.AddAttribute(FacilityCodeAttribute, facility); message.AddAttribute(SeverityCodeAttribute, severity); } if (OutText) { if (facility >= 0 && facility < FacilityText.Length) { message.AddAttribute(FacilityTextAttribute, FacilityText[facility]); } else { message.AddAttribute(FacilityTextAttribute, $"Unknown facility code{facility}"); } if (severity >= 0 && severity < SeverityText.Length) { message.AddAttribute(SeverityTextAttribute, SeverityText[severity]); } else { message.AddAttribute(SeverityTextAttribute, $"Unknown severity code{severity}"); } } }
protected void WorkerProc() { string[] allLines = File.ReadAllLines(@"C:\Temp\etc\storage.txt"); while (true) { Thread.Sleep(50); if (token.IsCancellationRequested) { break; } foreach (string line in allLines) { MessageDataItem message = new MessageDataItem(line); message.AddAttribute("ReciveTimestamp", DateTime.Now); while (!MessageSender.Invoke(message, true)) { Thread.Sleep(1); } if (token.IsCancellationRequested) { break; } } } }
public Variant GetValue(MessageDataItem dataItem) { if (Message) { return new Variant() { StringValue = dataItem.Message, Type = VariantType.String } } ; if (Value != null) { return(Value.Value); } if (Attribute != null) { Variant result = dataItem.GetAttributeAsVariant(Attribute.Name); if (result.Type != Attribute.Type) { throw new InvalidCastException("Attribute type mismatch."); } return(result); } throw new InvalidOperationException("Value Expression is not defined."); } }
public void ParseMessage(MessageDataItem message) { for (int o = 0; o < Outputs.Length; o++) { Outputs[o].AttachedQueue.TryAdd(message.Clone()); } }
public bool ProcessMessageShouldStop(MessageDataItem message) { try { bool filterMatch = FilterExpression?.Evaluate(message) ?? true; if (filterMatch) { Parser.ParseMessage(message); return(StopIfMatched); //if (stopIfMatched && filterMatch) // return true; // shall stop //else // return false; // shall proceed } else { return(false); // not matched => shall proceed } } catch (Exception e) { Server.Logger?.LogEvent(this, Severity.Error, "FilterAction", "Exception in filter", e); return(false); } }
private async Task SingleHostReceiver(Task <Socket> connectTask, object state) { Socket innerSocket = connectTask.Result; // bool isCancelled = false; int bytesRead = 0; StringBuilder stringBuilder = new StringBuilder(); byte[] buffer = new byte[bufferSize]; do { try { bytesRead = await innerSocket.ReceiveAsync(new ArraySegment <byte>(buffer), SocketFlags.None); } catch (OperationCanceledException) { // isCancelled = true; break; } if (bytesRead > 0) { string nextPortion = Encoding.ASCII.GetString(buffer, 0, bytesRead); int tailPos = nextPortion.IndexOfAny(TrailerChars); int headPos = 0; int len = nextPortion.Length; while (tailPos >= 0) { string thisMsg = nextPortion.Substring(headPos, tailPos - headPos).Trim(TrailerChars); stringBuilder.Append(thisMsg); MessageDataItem message = CreateMessageDataItem(stringBuilder.ToString(), innerSocket.RemoteEndPoint); while (!MessageSender.Invoke(message, true)) { Thread.Sleep(1); } stringBuilder.Clear(); headPos = tailPos + 1; while (headPos < len && TrailerChars.Any(c => c == nextPortion[headPos])) { headPos++; } if (headPos == len) { break; } tailPos = nextPortion.IndexOfAny(TrailerChars, headPos); } if (headPos < len) { stringBuilder.Append(nextPortion.Substring(headPos)); } } } while (bytesRead > 0); innerSocket?.Close(); }
private void ProcessMessage(MessageDataItem message) { for (int f = 0; f < FilterRuntime.Length; f++) { if (FilterRuntime[f].ProcessMessageShouldStop(message)) { break; } } }
private bool MessageAcceptor(MessageDataItem message, bool canPause) { for (int i = 0; i < AttributeCount; i++) { message.AddAttribute(Attibutes[i].Item1, Attibutes[i].Item2); } bool posted = AttachedQueue.TryAdd(message); if (!posted && !canPause) { Server.Logger?.LogEvent(InputModule, Severity.Warning, ServerConstants.Reasons.QueueOverflow, $"Input message dropped from '{ModuleKey}'. The module doesn't support input throttling."); Server.HealthReporter?.SetModuleHealth(InputModule, ServerConstants.Components.AttachedQueue, HealthState.Warning, "Message dropped"); } return(posted); }
public void ExtractAttributes(MessageDataItem message) { if (message.AttributeExists(InputAttribute) && !message.AttributeExists(OutputAttribute)) { try { IPAddress hostIPAddress = IPAddress.Parse(message.GetAttributeAsString(InputAttribute)); IPHostEntry hostInfo = Dns.GetHostEntry(hostIPAddress); message.AddAttribute(OutputAttribute, hostInfo.HostName); } catch { // none } } }
private string GetIndex(MessageDataItem msg) { try { return(msg.GetAttributeAsString(outputConfiguration.FieldMappings.IndexAttribute)); } catch { if (outputConfiguration.EventMetadataDefaults.Index != null) { return(outputConfiguration.EventMetadataDefaults.Index); } ServerLogger?.LogEvent(this, Severity.Warning, "SplunkHEC", "Failed to get index from message and no default index set, using main index instead."); return("main"); } }
private string GetHost(MessageDataItem msg) { try { return(msg.GetAttributeAsString(outputConfiguration.FieldMappings.HostAttribute)); } catch { if (outputConfiguration.EventMetadataDefaults.Host != null) { return(outputConfiguration.EventMetadataDefaults.Host); } ServerLogger?.LogEvent(this, Severity.Warning, "SplunkHEC", "Failed to get host from message and no default host, using localhost instead."); return("localhost"); } }
public bool Evaluate(MessageDataItem dataItem) { if (And != null) { return(And.All(x => x?.Evaluate(dataItem) == true)); } if (Or != null) { return(Or.Any(x => x?.Evaluate(dataItem) == true)); } if (Not != null) { return(!Not.Evaluate(dataItem)); } if (Exists != null) { if (Exists.Attribute != null) { if (dataItem.AttributeExists(Exists.Attribute.Name ?? "")) { if (dataItem.GetAttributeAsVariant(Exists.Attribute.Name).Type == Exists.Attribute.Type) { return(true); } } } } if (SimpleExpression != null) { return(SimpleExpression.Evaluate(dataItem)); } if (InExpression != null) { return(InExpression.Evaluate(dataItem)); } if (RegExExpression != null) { return(RegExExpression.Evaluate(dataItem)); } if (ModuleExpressionModule != null) { return(ModuleExpressionModule.IsMatch(dataItem)); } return(false); }
private string GetSource(MessageDataItem msg) { try { return(msg.GetAttributeAsString(outputConfiguration.FieldMappings.SourceAttribute)); } catch { if (outputConfiguration.EventMetadataDefaults.Source != null) { return(outputConfiguration.EventMetadataDefaults.Source); } ServerLogger?.LogEvent(this, Severity.Warning, "SplunkHEC", "Failed to get source from message and no default source set, using none instead."); return("none"); } }
protected MessageDataItem CreateMessageDataItem(string messageText, EndPoint endPoint) { MessageDataItem message = new MessageDataItem(messageText); if (AddSenderIPAttribute) { message.AddAttribute("SenderIP", (endPoint as IPEndPoint)?.Address.ToString()); } if (AddReciveTimestampAttribute && ReciveTimestampAttributeLocal) { message.AddAttribute("ReciveTimestamp", DateTime.Now); } if (AddReciveTimestampAttribute && !ReciveTimestampAttributeLocal) { message.AddAttribute("ReciveTimestamp", DateTime.UtcNow); } return(message); }
public void ExtractAttributes(MessageDataItem message) { try { if (string.IsNullOrWhiteSpace(message.Message) && AddDefaultIfNoPRI) { AddSyslogPRI(message, facility: DefaultFacility, severity: DefaultSeverity); return; } int maxSubLen = message.Message.Length > 20 ? 20 : message.Message.Length; string rawMessageHead = message.Message.Substring(0, maxSubLen).Trim(); if (string.IsNullOrWhiteSpace(rawMessageHead) && AddDefaultIfNoPRI) { AddSyslogPRI(message, facility: DefaultFacility, severity: DefaultSeverity); return; } if (rawMessageHead[0] == '<') { if (int.TryParse(rawMessageHead.Substring(1, rawMessageHead.IndexOf('>') - 1), out int priValue)) { int facility = priValue >> 3; int severity = priValue & 7; AddSyslogPRI(message, facility: facility, severity: severity); return; } } if (AddDefaultIfNoPRI) { AddSyslogPRI(message, facility: DefaultFacility, severity: DefaultSeverity); } return; } catch { { if (!message.AttributeExists("Facility") && !message.AttributeExists("Severity")) { AddSyslogPRI(message, facility: DefaultFacility, severity: DefaultSeverity); } } } }
public bool Evaluate(MessageDataItem dataItem) { Variant firstValue = FirstValue.GetValue(dataItem); Variant secondValue = SecondValue.GetValue(dataItem); switch (Operator) { case SimpleExpressionOperator.Equal: return(firstValue == secondValue); case SimpleExpressionOperator.NotEqual: return(firstValue != secondValue); case SimpleExpressionOperator.Greater: return(firstValue > secondValue); case SimpleExpressionOperator.GreaterEqual: return(firstValue >= secondValue); case SimpleExpressionOperator.Less: return(firstValue < secondValue); case SimpleExpressionOperator.LessEqual: return(firstValue <= secondValue); } return(false); }
private string GetEPOCHTime(MessageDataItem msg) { if (outputConfiguration.EventMetadataDefaults.UseCurrentTime) { return(DateTime.UtcNow.Subtract(epoch).TotalSeconds.ToString("F3")); } try { DateTime msgTime = msg.GetAttributeAsDateTime(outputConfiguration.FieldMappings.TimeAttribute); if (msgTime.Kind == DateTimeKind.Local) { msgTime = msgTime.ToUniversalTime(); } return(msgTime.Subtract(epoch).TotalSeconds.ToString("F3")); } catch { ServerLogger?.LogEvent(this, Severity.Warning, "SplunkHEC", "Failed to get time from message, using current time instead."); return(DateTime.Now.Subtract(epoch).TotalSeconds.ToString("F3")); } }
public bool Evaluate(MessageDataItem dataItem) { Variant firstValue = FirstValue.GetValue(dataItem); if (SecondValue?.Range != null) { switch (Operator) { case InExpressionOperator.In: return(firstValue > SecondValue?.Range.StartValue.GetValue(dataItem) && firstValue < SecondValue?.Range.EndValue.GetValue(dataItem)); case InExpressionOperator.InclusiveIn: return(firstValue >= SecondValue?.Range.StartValue.GetValue(dataItem) && firstValue <= SecondValue?.Range.EndValue.GetValue(dataItem)); case InExpressionOperator.NotIn: return(firstValue <= SecondValue?.Range.StartValue.GetValue(dataItem) && firstValue >= SecondValue?.Range.EndValue.GetValue(dataItem)); case InExpressionOperator.InclusiveNotIn: return(firstValue < SecondValue?.Range.StartValue.GetValue(dataItem) && firstValue > SecondValue?.Range.EndValue.GetValue(dataItem)); } } if (SecondValue.List != null) { switch (Operator) { case InExpressionOperator.In: case InExpressionOperator.InclusiveIn: return(SecondValue.List.Any(x => x?.GetValue(dataItem) == firstValue)); case InExpressionOperator.NotIn: case InExpressionOperator.InclusiveNotIn: return(SecondValue.List.All(x => x?.GetValue(dataItem) != firstValue)); } } return(false); }
public void ExtractAttributes(MessageDataItem message) { try { if (message.Message.IndexOf('=') == -1) { return; } // start state machine int pos = 0; int len = message.Message.Length; while (pos < len) { pos++; } return; } catch (Exception e) { ServerLogger?.LogEvent(this, Severity.Warning, "KVExtractor", "Error while extracting key-value pairs.", e); } }
} // null if message body public void SetField(GroupCollection groups, MessageDataItem inputMessage, ref string outMessage, Dictionary <string, Variant> outAttributes) { if (!string.IsNullOrEmpty(Input?.Group)) { string dynamicOutputAttribute; if (string.IsNullOrEmpty(Input.GroupToOutputAttribute)) { dynamicOutputAttribute = OutputAttribute; } else { dynamicOutputAttribute = groups[Input.GroupToOutputAttribute].Value; } switch (Input.Type) { case VariantType.Boolean: if (bool.TryParse(groups[Input.Group]?.Value, out bool newBoolValue)) { if (string.IsNullOrEmpty(dynamicOutputAttribute)) { outMessage = newBoolValue.ToString(); } else { outAttributes[dynamicOutputAttribute] = new Variant { BooleanValue = newBoolValue, Type = VariantType.Boolean } }; } return; case VariantType.DateTime: if (string.IsNullOrEmpty(Input.Format)) { if (DateTime.TryParse(groups[Input.Group]?.Value, out DateTime newDateTimeValue)) { if (string.IsNullOrEmpty(dynamicOutputAttribute)) { outMessage = newDateTimeValue.ToString(); } else { outAttributes[dynamicOutputAttribute] = new Variant { DateTimeValue = newDateTimeValue, Type = VariantType.DateTime } } } ; } else { if (DateTime.TryParseExact(groups[Input.Group]?.Value, Input.Format, null, DateTimeStyles.AssumeLocal, out DateTime newDateTimeValue)) { if (string.IsNullOrEmpty(dynamicOutputAttribute)) { outMessage = newDateTimeValue.ToString(); } else { outAttributes[dynamicOutputAttribute] = new Variant { DateTimeValue = newDateTimeValue, Type = VariantType.DateTime } } } ; } return; case VariantType.Float: if (float.TryParse(groups[Input.Group].Value, out float newFloatValue)) { if (string.IsNullOrEmpty(dynamicOutputAttribute)) { outMessage = (newFloatValue.ToString()); } else { outAttributes[dynamicOutputAttribute] = new Variant { FloatValue = newFloatValue, Type = VariantType.Float } } } ; return; case VariantType.Int: if (int.TryParse(groups[Input.Group].Value, out int newIntValue)) { if (string.IsNullOrEmpty(dynamicOutputAttribute)) { outMessage = (newIntValue.ToString()); } else { outAttributes[dynamicOutputAttribute] = new Variant { IntValue = newIntValue, Type = VariantType.Int } } } ; return; case VariantType.String: if (string.IsNullOrEmpty(dynamicOutputAttribute)) { outMessage = groups[Input.Group]?.Value ?? ""; } else { outAttributes[dynamicOutputAttribute] = new Variant { StringValue = groups[Input.Group]?.Value, Type = VariantType.String } }; return; } } if (Input?.Message == true) { if (string.IsNullOrEmpty(OutputAttribute)) { outMessage = inputMessage.Message; } else { outAttributes[OutputAttribute] = new Variant { StringValue = inputMessage.Message, Type = VariantType.String } }; return; } if (!string.IsNullOrEmpty(Input?.Attribute)) { if (string.IsNullOrEmpty(OutputAttribute)) { if (inputMessage.AttributeExists(Input.Attribute)) { outMessage = inputMessage.GetAttributeAsVariant(Input.Attribute).ToString(); } } else { if (inputMessage.AttributeExists(Input.Attribute)) { outAttributes[OutputAttribute] = inputMessage.GetAttributeAsVariant(Input.Attribute); } } return; } if (Input?.Value != null) { switch (Input.Type) { case VariantType.Boolean: if (bool.TryParse(Input.Value, out bool newBoolValue)) { if (string.IsNullOrEmpty(OutputAttribute)) { outMessage = newBoolValue.ToString(); } else { outAttributes[OutputAttribute] = new Variant { BooleanValue = newBoolValue, Type = VariantType.Boolean } }; } return; case VariantType.DateTime: if (string.IsNullOrEmpty(Input.Format)) { if (DateTime.TryParse(Input.Value, out DateTime newDateTimeValue)) { if (string.IsNullOrEmpty(OutputAttribute)) { outMessage = newDateTimeValue.ToString(); } else { outAttributes[OutputAttribute] = new Variant { DateTimeValue = newDateTimeValue, Type = VariantType.DateTime } } } ; } else { if (DateTime.TryParseExact(Input.Value, Input.Format, null, DateTimeStyles.AssumeLocal, out DateTime newDateTimeValue)) { if (string.IsNullOrEmpty(OutputAttribute)) { outMessage = newDateTimeValue.ToString(); } else { outAttributes[OutputAttribute] = new Variant { DateTimeValue = newDateTimeValue, Type = VariantType.DateTime } } } ; } return; case VariantType.Float: if (float.TryParse(Input.Value, out float newFloatValue)) { if (string.IsNullOrEmpty(OutputAttribute)) { outMessage = (newFloatValue.ToString()); } else { outAttributes[OutputAttribute] = new Variant { FloatValue = newFloatValue, Type = VariantType.Float } } } ; return; case VariantType.Int: if (int.TryParse(Input.Value, out int newIntValue)) { if (string.IsNullOrEmpty(OutputAttribute)) { outMessage = (newIntValue.ToString()); } else { outAttributes[OutputAttribute] = new Variant { IntValue = newIntValue, Type = VariantType.Int } } } ; return; case VariantType.String: if (string.IsNullOrEmpty(OutputAttribute)) { outMessage = Input.Value; } else { outAttributes[OutputAttribute] = new Variant { StringValue = Input.Value, Type = VariantType.String } }; return; } } } }
public void Enqueue(MessageDataItem message) { Messages.Enqueue(message); }
protected void WorkerProc() { EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); byte[] buffer = new byte[BufferSize]; while (true) { if (socket.SocketType == SocketType.Dgram) { Task <SocketReceiveFromResult> udpAsyncResult = socket.ReceiveFromAsync(new ArraySegment <byte>(buffer), SocketFlags.None, remoteEndPoint); try { udpAsyncResult.Wait(token); } catch (OperationCanceledException) { break; } int bytesReceived = udpAsyncResult.Result.ReceivedBytes; if (bytesReceived > 0) { MessageDataItem message = new MessageDataItem { Message = Encoding.ASCII.GetString(buffer, 0, bytesReceived) }; message.AddAttribute("SenderIP", (udpAsyncResult.Result.RemoteEndPoint as IPEndPoint)?.Address.ToString()); message.AddAttribute("ReciveTimestamp", DateTime.Now); message.AddAttribute("Channel", "UDP"); foreach (IQueueModule queue in OutputQueues) { queue.Enqueue(message); } } } if (socket.SocketType == SocketType.Stream) { Task <Socket> tcpAsyncAcceptResult = socket.AcceptAsync(); try { tcpAsyncAcceptResult.Wait(token); } catch { break; } Socket innerSocket = tcpAsyncAcceptResult.Result; bool isCancelled = false; StringBuilder stringBuilder = new StringBuilder(); int bytesRead = 0; do { Task <int> tcpAsyncReceiveResult = innerSocket.ReceiveAsync(new ArraySegment <byte>(buffer), SocketFlags.None); try { tcpAsyncReceiveResult.Wait(token); } catch { isCancelled = true; break; } bytesRead = tcpAsyncReceiveResult.Result; if (bytesRead > 0) { stringBuilder.Append(Encoding.ASCII.GetString(buffer, 0, tcpAsyncReceiveResult.Result)); } } while (bytesRead > 0); // propagate cancellation if (isCancelled) { break; } MessageDataItem message = new MessageDataItem { Message = stringBuilder.ToString() }; message.AddAttribute("SenderIP", (tcpAsyncAcceptResult.Result.RemoteEndPoint as IPEndPoint)?.Address.ToString()); message.AddAttribute("ReciveTimestamp", DateTime.Now); message.AddAttribute("Channel", "TCP"); foreach (IQueueModule queue in OutputQueues) { queue.Enqueue(message); } } } }
public MessageDataItem Parse(MessageDataItem message) { // result -- keep it as separate vars to allow modifications and overrides string outMessage = null; Dictionary <string, Variant> outAttributes = new Dictionary <string, Variant>(); bool AnyMatches = false; if (config.DefaultFieldSettings != null) { foreach (FieldSetting attrCfg in config.DefaultFieldSettings) { try { attrCfg.SetField(null, message, ref outMessage, outAttributes); } catch (Exception e) { ServerLogger?.LogEvent(this, Severity.Warning, "Parser", $"Failed to parse field {attrCfg.OutputAttribute ?? "<UNKNOWN>"}", e); } } } foreach (ParsingExpression expr in config.ParsingExpressions) { if (string.IsNullOrEmpty(expr.MatchingRegEx) || Regex.IsMatch(message.Message, expr.MatchingRegEx)) { MatchCollection matches = Regex.Matches(message.Message, expr.ParsingRegEx, expr.RegexOptions); if (matches.Count > 0) { AnyMatches = true; foreach (Match match in matches) { if (match.Success) { if (expr.FieldSettings != null) { foreach (FieldSetting attrCfg in expr.FieldSettings) { try { attrCfg.SetField(match.Groups, message, ref outMessage, outAttributes); } catch (Exception e) { ServerLogger?.LogEvent(this, Severity.Warning, "Parser", $"Failed to parse field {attrCfg.OutputAttribute ?? "<UNKNOWN>"}", e); } } } } } } else { if (expr.StopIfMatched) { ServerLogger?.LogEvent(this, Severity.Warning, "Parser", "Matching expression matched in a stopping expression, but the parsing expression didn't match."); } } // exit from loop of ParsingExpressions if (expr.StopIfMatched) { break; } } } if (AnyMatches) { MessageDataItem result = new MessageDataItem(outMessage ?? ""); foreach (KeyValuePair <string, Variant> newAttribute in outAttributes) { result.AddAttribute(newAttribute.Key, newAttribute.Value); } return(result); } else { if (config.PassthroughFieldSettings != null) { foreach (FieldSetting attrCfg in config.PassthroughFieldSettings) { try { attrCfg.SetField(null, message, ref outMessage, outAttributes); } catch (Exception e) { ServerLogger?.LogEvent(this, Severity.Warning, "Parser", $"Failed to parse field {attrCfg.OutputAttribute ?? "<UNKNOWN>"}", e); } } } MessageDataItem result = new MessageDataItem(outMessage ?? ""); foreach (KeyValuePair <string, Variant> newAttribute in outAttributes) { result.AddAttribute(newAttribute.Key, newAttribute.Value); } return(result); // return message.Clone(); } }