Example #1
0
        /// <summary>
        /// Sends a log message to Loggly.
        /// </summary>
        /// <param name="fullyQualifiedDomainName">The fully qualified domain name of the originator.  Can be null in the rare case that it's unknown.</param>
        /// <param name="applicationName">The name of the application that originated the message.  Can be null if unknown or explicitly withheld.</param>
        /// <param name="processIdentifier">The process name or process identifier, having no interoperable meaning, except that a change in the value indicates that there has been a discontinuity in the syslog reporting.  Can also be used to identify which messages belong to a group of messages.  Can be null if not available.</param>
        /// <param name="severity">The severity of the log message.</param>
        /// <param name="timestamp">The timestamp of the message, in UTC.</param>
        /// <param name="messagePayload">The message payload.  Can be as simple as a string message (e.g. "something happened") or an object serialized to json.</param>
        /// <param name="messageType">The type of message.  Can be null if unknown or not applicable.</param>
        /// <param name="logglyTags">Optional Loggly-compliant tags to apply to the log message.  Default is null (no tags).</param>
        public static void SendLogMessageToLoggly(
            string fullyQualifiedDomainName,
            string applicationName,
            string processIdentifier,
            Severity severity,
            DateTime timestamp,
            string messagePayload,
            string messageType,
            IReadOnlyCollection <LogglyTag> logglyTags = null)
        {
            if (settings == null)
            {
                throw new InvalidOperationException(Invariant($"{nameof(Initialize)} has not yet been called."));
            }

            logglyTags = logglyTags?.Where(_ => _ != null).ToList() ?? new List <LogglyTag>();

            // build the syslog message and queue-up
            var structuredDataId = settings.CustomerToken + "@" + settings.LogglyPrivateEnterpriseNumber;

            // add tags to structured data
            IReadOnlyList <KeyValuePair <string, string> > structuredData = null;

            if (logglyTags.Any())
            {
                structuredData = logglyTags.Select(_ => new KeyValuePair <string, string>("tag", _.Tag)).ToList();
            }

            // build the syslog message and queue up
            var messageBytes = SyslogMessageBuilder.BuildRfc5424Message(fullyQualifiedDomainName, applicationName, processIdentifier, timestamp, settings.Facility, severity, messagePayload, false, messageType, structuredDataId, structuredData);

            SendLogMessageToLoggly(messageBytes);
        }
Example #2
0
        public static void BuildRfc5424Message___MessageIsNotNullAndUtf8EncodingIsTrue_MessageIsEncodedWithBomFollowedByUtf8StringAndAddedToTailWithNewLineTerminator()
        {
            // Arrange
            const bool   EnecodeMessageInUtf8 = true;
            const string Message        = "Tюhiસs iϖs my mஇeύᄻ";
            var          structuredData = new List <KeyValuePair <string, string> >
            {
                new KeyValuePair <string, string>("myName1", "myValue1"),
            };

            const string StructuredDataId = "ThisIsMy@Identifier";
            var          timeStamp        = new DateTime(2014, 5, 20, 7, 42, 6, 83, DateTimeKind.Utc);
            string       expectedHeader   = string.Format("<188>1 2014-05-20T07:42:06.083Z {0} {1} {2} - [{3} myName1=\"myValue1\"] ", GetFullyQualifiedDomainName(), Process.GetCurrentProcess().ProcessName, Process.GetCurrentProcess().Id, StructuredDataId);

            byte[] expected =
                Encoding.ASCII.GetBytes(expectedHeader)
                .Concat(Encoding.UTF8.GetPreamble())
                .Concat(Encoding.UTF8.GetBytes(Message + "\n"))
                .ToArray();

            // Act
            byte[] message = SyslogMessageBuilder.BuildRfc5424Message(FullyQualifiedDomainName, ApplicationName, ProcessId, timeStamp, Facility.Local7, Severity.Warning, Message, EnecodeMessageInUtf8, null, StructuredDataId, structuredData);

            // Assert
            Assert.True(message.SequenceEqual(expected));
        }
Example #3
0
        public static void BuildRfc5424Message___MessageIsNull_LastElementInEncodedMessageIsStructuredDataTerminatedWithNewLine()
        {
            // Arrange
            var structuredData = new List <KeyValuePair <string, string> >
            {
                new KeyValuePair <string, string>("myName1", "myValue1"),
                new KeyValuePair <string, string>("myName2", "myValue2"),
                new KeyValuePair <string, string>("myName3", "myValue3"),
            };

            const string StructuredDataId = "ThisIsMy@Identifier";
            var          timeStamp        = new DateTime(2014, 5, 20, 7, 42, 6, 83, DateTimeKind.Utc);
            string       expectedHeader   = string.Format("<188>1 2014-05-20T07:42:06.083Z {0} {1} {2} -", GetFullyQualifiedDomainName(), Process.GetCurrentProcess().ProcessName, Process.GetCurrentProcess().Id);
            string       expectedHeader1  = expectedHeader + " [ThisIsMy@Identifier myName1=\"myValue1\" myName2=\"myValue2\" myName3=\"myValue3\"]\n";
            string       expectedHeader2  = expectedHeader + " -\n";

            byte[] expected1 = Encoding.ASCII.GetBytes(expectedHeader1);
            byte[] expected2 = Encoding.ASCII.GetBytes(expectedHeader2);

            // Act
            byte[] message1 = SyslogMessageBuilder.BuildRfc5424Message(FullyQualifiedDomainName, ApplicationName, ProcessId, timeStamp, Facility.Local7, Severity.Warning, null, true, null, StructuredDataId, structuredData);
            byte[] message2 = SyslogMessageBuilder.BuildRfc5424Message(FullyQualifiedDomainName, ApplicationName, ProcessId, timeStamp, Facility.Local7, Severity.Warning, null, true, null, null, structuredData);

            // Assert
            Assert.True(message1.SequenceEqual(expected1));
            Assert.True(message2.SequenceEqual(expected2));
        }
Example #4
0
        public static void BuildRfc5424Message___ProperlyEncodesPriorityFromFacilityAndSeverityInHeader()
        {
            // Arrange
            byte[] expected1 = Encoding.ASCII.GetBytes("<0>");
            byte[] expected2 = Encoding.ASCII.GetBytes("<4>");
            byte[] expected3 = Encoding.ASCII.GetBytes("<7>");

            byte[] expected4 = Encoding.ASCII.GetBytes("<184>");
            byte[] expected5 = Encoding.ASCII.GetBytes("<188>");
            byte[] expected6 = Encoding.ASCII.GetBytes("<191>");

            byte[] expected7 = Encoding.ASCII.GetBytes("<64>");
            byte[] expected8 = Encoding.ASCII.GetBytes("<68>");
            byte[] expected9 = Encoding.ASCII.GetBytes("<71>");

            byte[] expected10 = Encoding.ASCII.GetBytes("<120>");
            byte[] expected11 = Encoding.ASCII.GetBytes("<124>");
            byte[] expected12 = Encoding.ASCII.GetBytes("<127>");

            // Act
            byte[] message1 = SyslogMessageBuilder.BuildRfc5424Message(FullyQualifiedDomainName, ApplicationName, ProcessId, DateTime.UtcNow, Facility.Kernel, Severity.Emergency, "my message", true, null, null, null);
            byte[] message2 = SyslogMessageBuilder.BuildRfc5424Message(FullyQualifiedDomainName, ApplicationName, ProcessId, DateTime.UtcNow, Facility.Kernel, Severity.Warning, "my message", true, null, null, null);
            byte[] message3 = SyslogMessageBuilder.BuildRfc5424Message(FullyQualifiedDomainName, ApplicationName, ProcessId, DateTime.UtcNow, Facility.Kernel, Severity.Debug, "my message", true, null, null, null);

            byte[] message4 = SyslogMessageBuilder.BuildRfc5424Message(FullyQualifiedDomainName, ApplicationName, ProcessId, DateTime.UtcNow, Facility.Local7, Severity.Emergency, "my message", true, null, null, null);
            byte[] message5 = SyslogMessageBuilder.BuildRfc5424Message(FullyQualifiedDomainName, ApplicationName, ProcessId, DateTime.UtcNow, Facility.Local7, Severity.Warning, "my message", true, null, null, null);
            byte[] message6 = SyslogMessageBuilder.BuildRfc5424Message(FullyQualifiedDomainName, ApplicationName, ProcessId, DateTime.UtcNow, Facility.Local7, Severity.Debug, "my message", true, null, null, null);

            byte[] message7 = SyslogMessageBuilder.BuildRfc5424Message(FullyQualifiedDomainName, ApplicationName, ProcessId, DateTime.UtcNow, Facility.Uucp, Severity.Emergency, "my message", true, null, null, null);
            byte[] message8 = SyslogMessageBuilder.BuildRfc5424Message(FullyQualifiedDomainName, ApplicationName, ProcessId, DateTime.UtcNow, Facility.Uucp, Severity.Warning, "my message", true, null, null, null);
            byte[] message9 = SyslogMessageBuilder.BuildRfc5424Message(FullyQualifiedDomainName, ApplicationName, ProcessId, DateTime.UtcNow, Facility.Uucp, Severity.Debug, "my message", true, null, null, null);

            byte[] message10 = SyslogMessageBuilder.BuildRfc5424Message(FullyQualifiedDomainName, ApplicationName, ProcessId, DateTime.UtcNow, Facility.Clock2, Severity.Emergency, "my message", true, null, null, null);
            byte[] message11 = SyslogMessageBuilder.BuildRfc5424Message(FullyQualifiedDomainName, ApplicationName, ProcessId, DateTime.UtcNow, Facility.Clock2, Severity.Warning, "my message", true, null, null, null);
            byte[] message12 = SyslogMessageBuilder.BuildRfc5424Message(FullyQualifiedDomainName, ApplicationName, ProcessId, DateTime.UtcNow, Facility.Clock2, Severity.Debug, "my message", true, null, null, null);

            // Assert
            Assert.True(message1.Take(expected1.Length).SequenceEqual(expected1));
            Assert.True(message2.Take(expected2.Length).SequenceEqual(expected2));
            Assert.True(message3.Take(expected3.Length).SequenceEqual(expected3));

            Assert.True(message4.Take(expected4.Length).SequenceEqual(expected4));
            Assert.True(message5.Take(expected5.Length).SequenceEqual(expected5));
            Assert.True(message6.Take(expected6.Length).SequenceEqual(expected6));

            Assert.True(message7.Take(expected7.Length).SequenceEqual(expected7));
            Assert.True(message8.Take(expected8.Length).SequenceEqual(expected8));
            Assert.True(message9.Take(expected9.Length).SequenceEqual(expected9));

            Assert.True(message10.Take(expected10.Length).SequenceEqual(expected10));
            Assert.True(message11.Take(expected11.Length).SequenceEqual(expected11));
            Assert.True(message12.Take(expected12.Length).SequenceEqual(expected12));
        }
Example #5
0
        public static void BuildRfc5424Message___Should_use_Nil_for_PROCID___When_processIdentifier_is_null()
        {
            // Arrange
            var timeStamp = new DateTime(2014, 5, 20, 7, 42, 6, 83, DateTimeKind.Utc);
            var expected  = Encoding.ASCII.GetBytes($"<188>1 2014-05-20T07:42:06.083Z {FullyQualifiedDomainName} {ApplicationName} -");

            // Act
            var actual = SyslogMessageBuilder.BuildRfc5424Message(FullyQualifiedDomainName, ApplicationName, null, timeStamp, Facility.Local7, Severity.Warning, "my message", true, null, null, null);

            // Assert
            actual.Take(expected.Length).Should().Equal(expected);
        }
Example #6
0
        public static void BuildRfc5424Message___ProperlyEncodesHostNameAppNameAndProcessIdInHeader()
        {
            // Arrange
            var timeStamp = new DateTime(2014, 5, 20, 7, 42, 6, 83, DateTimeKind.Utc);

            byte[] expected = Encoding.ASCII.GetBytes($"<188>1 2014-05-20T07:42:06.083Z {FullyQualifiedDomainName} {ApplicationName} {ProcessId}");

            // Act
            byte[] message = SyslogMessageBuilder.BuildRfc5424Message(FullyQualifiedDomainName, ApplicationName, ProcessId, timeStamp, Facility.Local7, Severity.Warning, "my message", true, null, null, null);

            // Assert
            Assert.True(message.Take(expected.Length).SequenceEqual(expected));
        }
Example #7
0
        public static void BuildRfc5424Message___StructuredDataParams_IsNull_NotIncludedInStructuredData()
        {
            // Arrange
            const string StructuredDataId = "ThisIsMy@Identifier";
            var          timeStamp        = new DateTime(2014, 5, 20, 7, 42, 6, 83, DateTimeKind.Utc);
            string       expectedHeader   = string.Format("<188>1 2014-05-20T07:42:06.083Z {0} {1} {2} - [{3}]", GetFullyQualifiedDomainName(), Process.GetCurrentProcess().ProcessName, Process.GetCurrentProcess().Id, StructuredDataId);

            byte[] expected = Encoding.ASCII.GetBytes(expectedHeader);

            // Act
            byte[] message = SyslogMessageBuilder.BuildRfc5424Message(FullyQualifiedDomainName, ApplicationName, ProcessId, timeStamp, Facility.Local7, Severity.Warning, "my message", true, null, StructuredDataId, null);

            // Assert
            Assert.True(message.Take(expected.Length).SequenceEqual(expected));
        }
Example #8
0
        public static void BuildRfc5424Message___WhenMessageIdIsNull_InsertsNilInHeader()
        {
            // Arrange
            var    timeStamp      = new DateTime(2014, 5, 20, 7, 42, 6, 83, DateTimeKind.Utc);
            string expectedHeader = string.Format("<188>1 2014-05-20T07:42:06.083Z {0} {1} {2}", GetFullyQualifiedDomainName(), Process.GetCurrentProcess().ProcessName, Process.GetCurrentProcess().Id);

            expectedHeader = expectedHeader + " -";
            byte[] expected = Encoding.ASCII.GetBytes(expectedHeader);

            // Act
            byte[] message = SyslogMessageBuilder.BuildRfc5424Message(FullyQualifiedDomainName, ApplicationName, ProcessId, timeStamp, Facility.Local7, Severity.Warning, "my message", true, null, null, null);

            // Assert
            Assert.True(message.Take(expected.Length).SequenceEqual(expected));
        }
Example #9
0
        public static void BuildRfc5424Message___WhenMessageIdContainsMoreThan32Characters_InsertsMessageIdTruncatedTo32Characters()
        {
            // Arrange
            const string MessageId      = "asdfg  hkl;qwertyuiop{]<.sdcvn.zxmncvb";
            var          timeStamp      = new DateTime(2014, 5, 20, 7, 42, 6, 83, DateTimeKind.Utc);
            string       expectedHeader = string.Format("<188>1 2014-05-20T07:42:06.083Z {0} {1} {2}", GetFullyQualifiedDomainName(), Process.GetCurrentProcess().ProcessName, Process.GetCurrentProcess().Id);

            expectedHeader = expectedHeader + " " + "asdfghkl;qwertyuiop{]<.sdcvn.zxm";
            byte[] expected = Encoding.ASCII.GetBytes(expectedHeader);

            // Act
            byte[] message = SyslogMessageBuilder.BuildRfc5424Message(FullyQualifiedDomainName, ApplicationName, ProcessId, timeStamp, Facility.Local7, Severity.Warning, "my message", true, MessageId, null, null);

            // Assert
            Assert.True(message.Take(expected.Length).SequenceEqual(expected));
        }
Example #10
0
        public static void BuildRfc5424Message___WhenMessageIdContainsAsciiCharactersOutsideOf32To126_InsertsMessageIdWithInvalidCharactersRemoved()
        {
            // Arrange
            string messageId      = "2!z )!@#$%" + ((char)1) + ((char)2) + "^&*" + ((char)31) + "()3a" + ((char)127);
            var    timeStamp      = new DateTime(2014, 5, 20, 7, 42, 6, 83, DateTimeKind.Utc);
            string expectedHeader = string.Format("<188>1 2014-05-20T07:42:06.083Z {0} {1} {2}", GetFullyQualifiedDomainName(), Process.GetCurrentProcess().ProcessName, Process.GetCurrentProcess().Id);

            expectedHeader = expectedHeader + " " + "2!z)!@#$%^&*()3a";
            byte[] expected = Encoding.ASCII.GetBytes(expectedHeader);

            // Act
            byte[] message = SyslogMessageBuilder.BuildRfc5424Message(FullyQualifiedDomainName, ApplicationName, ProcessId, timeStamp, Facility.Local7, Severity.Warning, "my message", true, messageId, null, null);

            // Assert
            Assert.True(message.Take(expected.Length).SequenceEqual(expected));
        }
Example #11
0
        public static void BuildRfc5424Message___ProperlyEncodesVersionAndTimestampInHeader()
        {
            // Arrange
            var timeStamp1 = new DateTime(2014, 5, 20, 7, 42, 6, 83, DateTimeKind.Utc);

            byte[] expected1 = Encoding.ASCII.GetBytes("<188>1 2014-05-20T07:42:06.083Z");

            var timeStamp2 = new DateTime(2014, 10, 2, 14, 5, 39, 841, DateTimeKind.Utc);

            byte[] expected2 = Encoding.ASCII.GetBytes("<188>1 2014-10-02T14:05:39.841Z");

            // Act
            byte[] message1 = SyslogMessageBuilder.BuildRfc5424Message(FullyQualifiedDomainName, ApplicationName, ProcessId, timeStamp1, Facility.Local7, Severity.Warning, "my message", true, null, null, null);
            byte[] message2 = SyslogMessageBuilder.BuildRfc5424Message(FullyQualifiedDomainName, ApplicationName, ProcessId, timeStamp2, Facility.Local7, Severity.Warning, "my message", true, null, null, null);

            // Assert
            Assert.True(message1.Take(expected1.Length).SequenceEqual(expected1));
            Assert.True(message2.Take(expected2.Length).SequenceEqual(expected2));
        }
Example #12
0
        public static void BuildRfc5424Message___StructuredDataParamValueContainsCharactersThatMustBeEscaped_CharactersAreEscaped()
        {
            // Arrange
            var structuredData = new List <KeyValuePair <string, string> >
            {
                new KeyValuePair <string, string>("myName1", "val\"id]val\\id"),
            };

            const string StructuredDataId = "ThisIsMy@Identifier";
            var          timeStamp        = new DateTime(2014, 5, 20, 7, 42, 6, 83, DateTimeKind.Utc);
            string       expectedHeader   = string.Format("<188>1 2014-05-20T07:42:06.083Z {0} {1} {2} - [{3}", GetFullyQualifiedDomainName(), Process.GetCurrentProcess().ProcessName, Process.GetCurrentProcess().Id, StructuredDataId);

            expectedHeader = expectedHeader + " myName1=\"val\\\"id\\]val\\\\id\"]";

            byte[] expected = Encoding.ASCII.GetBytes(expectedHeader);

            // Act
            byte[] message = SyslogMessageBuilder.BuildRfc5424Message(FullyQualifiedDomainName, ApplicationName, ProcessId, timeStamp, Facility.Local7, Severity.Warning, "my message", true, null, StructuredDataId, structuredData);

            // Assert
            Assert.True(message.Take(expected.Length).SequenceEqual(expected));
        }
Example #13
0
        public static void BuildRfc5424Message___StructuredDataParamNameContainsMoreThan32ValidCharacters_ParamNameTruncatedTo32Characters()
        {
            // Arrange
            var structuredData = new List <KeyValuePair <string, string> >
            {
                new KeyValuePair <string, string>("= myName]\"asdfghjkl;'qwertyuiop$#()*^!@12395813", "value2"),
            };

            const string StructuredDataId = "ThisIsMy@Identifier";
            var          timeStamp        = new DateTime(2014, 5, 20, 7, 42, 6, 83, DateTimeKind.Utc);
            string       expectedHeader   = string.Format("<188>1 2014-05-20T07:42:06.083Z {0} {1} {2} - [{3}", GetFullyQualifiedDomainName(), Process.GetCurrentProcess().ProcessName, Process.GetCurrentProcess().Id, StructuredDataId);

            expectedHeader = expectedHeader + " myNameasdfghjkl;'qwertyuiop$#()*=";

            byte[] expected = Encoding.ASCII.GetBytes(expectedHeader);

            // Act
            byte[] message = SyslogMessageBuilder.BuildRfc5424Message(FullyQualifiedDomainName, ApplicationName, ProcessId, timeStamp, Facility.Local7, Severity.Warning, "my message", true, null, StructuredDataId, structuredData);

            // Assert
            Assert.True(message.Take(expected.Length).SequenceEqual(expected));
        }
Example #14
0
        public static void BuildRfc5424Message___MessageIsNotNullAndUtf8EncodingIsFalse_MessageIsEncodedInAsciiAndAddedToTailWithNewLineTerminator()
        {
            // Arrange
            const bool   EnecodeMessageInUtf8 = false;
            const string Message        = "This is my messageDKLJ!!@#$%^&*()-=+_[]{}';/,";
            var          structuredData = new List <KeyValuePair <string, string> >
            {
                new KeyValuePair <string, string>("myName1", "myValue1"),
            };

            const string StructuredDataId = "ThisIsMy@Identifier";
            var          timeStamp        = new DateTime(2014, 5, 20, 7, 42, 6, 83, DateTimeKind.Utc);
            string       expectedHeader   = string.Format("<188>1 2014-05-20T07:42:06.083Z {0} {1} {2} - [{3} myName1=\"myValue1\"]", GetFullyQualifiedDomainName(), Process.GetCurrentProcess().ProcessName, Process.GetCurrentProcess().Id, StructuredDataId);

            expectedHeader = expectedHeader + " " + Message + "\n";
            byte[] expected = Encoding.ASCII.GetBytes(expectedHeader);

            // Act
            byte[] message = SyslogMessageBuilder.BuildRfc5424Message(FullyQualifiedDomainName, ApplicationName, ProcessId, timeStamp, Facility.Local7, Severity.Warning, Message, EnecodeMessageInUtf8, null, StructuredDataId, structuredData);

            // Assert
            Assert.True(message.SequenceEqual(expected));
        }
Example #15
0
        public static void BuildRfc5424Message___StructuredDataParamsNamesAreAllNullOrEmptyOrContainAllInvalidCharacters_NoParamsIncludedInStructuredData()
        {
            // Arrange
            var structuredData = new List <KeyValuePair <string, string> >
            {
                new KeyValuePair <string, string>(null, "value1"),
                new KeyValuePair <string, string>("= ]\"", "value2"),
                new KeyValuePair <string, string>(string.Empty, "value2"),
                new KeyValuePair <string, string>(" \r\n   ", "value2"),
                new KeyValuePair <string, string>(null, "value3"),
            };

            const string StructuredDataId = "ThisIsMy@Identifier";
            var          timeStamp        = new DateTime(2014, 5, 20, 7, 42, 6, 83, DateTimeKind.Utc);
            string       expectedHeader   = string.Format("<188>1 2014-05-20T07:42:06.083Z {0} {1} {2} - [{3}]", GetFullyQualifiedDomainName(), Process.GetCurrentProcess().ProcessName, Process.GetCurrentProcess().Id, StructuredDataId);

            byte[] expected = Encoding.ASCII.GetBytes(expectedHeader);

            // Act
            byte[] message = SyslogMessageBuilder.BuildRfc5424Message(FullyQualifiedDomainName, ApplicationName, ProcessId, timeStamp, Facility.Local7, Severity.Warning, "my message", true, null, StructuredDataId, structuredData);

            // Assert
            Assert.True(message.Take(expected.Length).SequenceEqual(expected));
        }
Example #16
0
        public static void BuildRfc5424Message___Should_throw_ArgumentException___When_parameter_timestamp_DateTimeKind_is_not_Utc()
        {
            // Arrange
            var timestamp1          = new DateTime(1, DateTimeKind.Local);
            var timestamp2          = new DateTime(1, DateTimeKind.Unspecified);
            var facility            = A.Dummy <Facility>();
            var severity            = A.Dummy <Severity>();
            var logMessage          = A.Dummy <string>();
            var encodeMessageInUtf8 = A.Dummy <bool>();
            var messageId           = A.Dummy <string>();
            var structuredDataId    = A.Dummy <string>();
            var structuredData      = Some.ReadOnlyDummies <KeyValuePair <string, string> >();

            // Act
            var ex1 = Record.Exception(() => SyslogMessageBuilder.BuildRfc5424Message(FullyQualifiedDomainName, ApplicationName, ProcessId, timestamp1, facility, severity, logMessage, encodeMessageInUtf8, messageId, structuredDataId, structuredData));
            var ex2 = Record.Exception(() => SyslogMessageBuilder.BuildRfc5424Message(FullyQualifiedDomainName, ApplicationName, ProcessId, timestamp2, facility, severity, logMessage, encodeMessageInUtf8, messageId, structuredDataId, structuredData));

            // Assert
            ex1.Should().BeOfType <ArgumentException>();
            ex1.Message.Should().Be("timestamp.Kind is Local, expecting Utc.");

            ex2.Should().BeOfType <ArgumentException>();
            ex2.Message.Should().Be("timestamp.Kind is Unspecified, expecting Utc.");
        }