diff --git a/sdk/monitor/Azure.Monitor.Query/CHANGELOG.md b/sdk/monitor/Azure.Monitor.Query/CHANGELOG.md index c5cf028fea3a..06bd90599dc4 100644 --- a/sdk/monitor/Azure.Monitor.Query/CHANGELOG.md +++ b/sdk/monitor/Azure.Monitor.Query/CHANGELOG.md @@ -1,14 +1,9 @@ # Release History -## 1.1.0-beta.1 (Unreleased) - +## 1.1.0 (2021-12-07) ### Features Added +- Added `LogsTable` and `LogsTableRow` to `MonitorQueryModelFactory` -### Breaking Changes - -### Bugs Fixed - -### Other Changes ## 1.0.1 (2021-11-09) diff --git a/sdk/monitor/Azure.Monitor.Query/api/Azure.Monitor.Query.netstandard2.0.cs b/sdk/monitor/Azure.Monitor.Query/api/Azure.Monitor.Query.netstandard2.0.cs index 95ee6bc86fe7..c0c6b142d58f 100644 --- a/sdk/monitor/Azure.Monitor.Query/api/Azure.Monitor.Query.netstandard2.0.cs +++ b/sdk/monitor/Azure.Monitor.Query/api/Azure.Monitor.Query.netstandard2.0.cs @@ -343,7 +343,9 @@ internal MetricValue() { } public static partial class MonitorQueryModelFactory { public static Azure.Monitor.Query.Models.LogsQueryResult LogsQueryResult(System.Collections.Generic.IReadOnlyList allTables, System.BinaryData statistics, System.BinaryData visualization, System.BinaryData error) { throw null; } + public static Azure.Monitor.Query.Models.LogsTable LogsTable(string name, System.Collections.Generic.IEnumerable columns, System.Collections.Generic.IEnumerable rows) { throw null; } public static Azure.Monitor.Query.Models.LogsTableColumn LogsTableColumn(string name = null, Azure.Monitor.Query.Models.LogsColumnType type = default(Azure.Monitor.Query.Models.LogsColumnType)) { throw null; } + public static Azure.Monitor.Query.Models.LogsTableRow LogsTableRow(System.Collections.Generic.IEnumerable columns, System.Collections.Generic.IEnumerable values) { throw null; } public static Azure.Monitor.Query.Models.MetricAvailability MetricAvailability(System.TimeSpan? granularity = default(System.TimeSpan?), System.TimeSpan? retention = default(System.TimeSpan?)) { throw null; } public static Azure.Monitor.Query.Models.MetricsQueryResult MetricsQueryResult(int? cost, string timespan, System.TimeSpan? granularity, string @namespace, string resourceRegion, System.Collections.Generic.IReadOnlyList metrics) { throw null; } public static Azure.Monitor.Query.Models.MetricValue MetricValue(System.DateTimeOffset timeStamp = default(System.DateTimeOffset), double? average = default(double?), double? minimum = default(double?), double? maximum = default(double?), double? total = default(double?), double? count = default(double?)) { throw null; } diff --git a/sdk/monitor/Azure.Monitor.Query/src/Azure.Monitor.Query.csproj b/sdk/monitor/Azure.Monitor.Query/src/Azure.Monitor.Query.csproj index b8ff19efee89..f78f929af20d 100644 --- a/sdk/monitor/Azure.Monitor.Query/src/Azure.Monitor.Query.csproj +++ b/sdk/monitor/Azure.Monitor.Query/src/Azure.Monitor.Query.csproj @@ -2,7 +2,7 @@ A library for querying Azure Monitor's Logs and Metrics data sources. Azure Monitor Query client library - 1.1.0-beta.1 + 1.1.0 1.0.1 Azure Monitor Query diff --git a/sdk/monitor/Azure.Monitor.Query/src/Models/LogsTableColumn.cs b/sdk/monitor/Azure.Monitor.Query/src/Models/LogsTableColumn.cs new file mode 100644 index 000000000000..c743386c91bb --- /dev/null +++ b/sdk/monitor/Azure.Monitor.Query/src/Models/LogsTableColumn.cs @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Collections.Generic; +using System.Linq; +using Azure.Core; + +namespace Azure.Monitor.Query.Models +{ + [CodeGenModel("Column")] + public partial class LogsTableColumn + { + /// + public override string ToString() + { + return $"{Name} ({Type})"; + } + + internal static Dictionary GetColumnMapFromColumns(IEnumerable columns) + { + Dictionary columnMap = new(); + var columnsList = columns.ToArray(); + for (var index = 0; index < columnsList.Length; index++) + { + columnMap[columnsList[index].Name] = index; + } + return columnMap; + } + } +} diff --git a/sdk/monitor/Azure.Monitor.Query/src/Models/LogsTableRow.cs b/sdk/monitor/Azure.Monitor.Query/src/Models/LogsTableRow.cs index 4f247b201871..ce8976aad478 100644 --- a/sdk/monitor/Azure.Monitor.Query/src/Models/LogsTableRow.cs +++ b/sdk/monitor/Azure.Monitor.Query/src/Models/LogsTableRow.cs @@ -18,7 +18,7 @@ public class LogsTableRow: IReadOnlyList { private readonly Dictionary _columnMap; private readonly IReadOnlyList _columns; - private readonly JsonElement _row; + internal JsonElement _row; internal LogsTableRow(Dictionary columnMap, IReadOnlyList columns, JsonElement row) { diff --git a/sdk/monitor/Azure.Monitor.Query/src/Models/MonitorQueryModelFactory.cs b/sdk/monitor/Azure.Monitor.Query/src/Models/MonitorQueryModelFactory.cs index 5c95fcaa3cb4..527d4a883a2c 100644 --- a/sdk/monitor/Azure.Monitor.Query/src/Models/MonitorQueryModelFactory.cs +++ b/sdk/monitor/Azure.Monitor.Query/src/Models/MonitorQueryModelFactory.cs @@ -3,7 +3,11 @@ using System; using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; using System.Text.Json; +using Azure.Monitor.Query.Models; namespace Azure.Monitor.Query.Models { @@ -12,7 +16,7 @@ namespace Azure.Monitor.Query.Models /// public static partial class MonitorQueryModelFactory { - /// Initializes a new instance of MetricsQueryResult. + /// Enables the user to create an instance of a . /// The integer value representing the relative cost of the query. /// The timespan for which the data was retrieved. Its value consists of two datetimes concatenated, separated by '/'. This may be adjusted in the future and returned back from what was originally requested. /// The interval (window size) for which the metric data was returned in. This may be adjusted in the future and returned back from what was originally requested. This is not present if a metadata request was made. @@ -24,7 +28,7 @@ public static MetricsQueryResult MetricsQueryResult(int? cost, string timespan, return new MetricsQueryResult(cost, timespan, granularity, @namespace, resourceRegion, metrics); } - /// Initializes a new instance of LogsQueryResult. + /// Enables the user to create an instance of a . /// The list of tables, columns and rows. /// Any object. /// Any object. @@ -36,5 +40,45 @@ public static LogsQueryResult LogsQueryResult(IReadOnlyList allTables JsonElement errorJson = error.ToObjectFromJson(); return new LogsQueryResult(allTables, statisticsJson, visualizationJson, errorJson); } + + /// Enables the user to create an instance of a . + /// The list of columns. + /// An object array representing the rows of the table. + /// A new instance for mocking. + public static LogsTableRow LogsTableRow(IEnumerable columns, IEnumerable values) + { + var columnsList = columns.ToArray(); + var columnMap = Models.LogsTableColumn.GetColumnMapFromColumns(columns); + JsonElement row = JsonElementFromObject(values); + return new LogsTableRow(columnMap, columnsList, row); + } + + /// Enables the user to create an instance of a . + /// The name of the table. + /// The list of columns. + /// The list of rows. + /// or is null. + public static LogsTable LogsTable(string name, IEnumerable columns, IEnumerable rows) + { + using MemoryStream stream = new MemoryStream(); + using Utf8JsonWriter writer = new Utf8JsonWriter(stream); + writer.WriteStartArray(); + foreach (var row in rows) + { + row._row.WriteTo(writer); + } + writer.WriteEndArray(); + writer.Flush(); + var doc = JsonDocument.Parse(stream.ToArray()); + var logsTableRow = doc.RootElement.Clone(); + return new LogsTable(name, columns, logsTableRow); + } + + private static JsonElement JsonElementFromObject(TValue value, JsonSerializerOptions options = default) + { + var bytes = JsonSerializer.SerializeToUtf8Bytes(value, options); + var doc = JsonDocument.Parse(bytes); + return doc.RootElement.Clone(); + } } } diff --git a/sdk/monitor/Azure.Monitor.Query/src/Models/QueryResultColumn.cs b/sdk/monitor/Azure.Monitor.Query/src/Models/QueryResultColumn.cs deleted file mode 100644 index 9bff8c090858..000000000000 --- a/sdk/monitor/Azure.Monitor.Query/src/Models/QueryResultColumn.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using Azure.Core; - -namespace Azure.Monitor.Query.Models -{ - [CodeGenModel("Column")] - public partial class LogsTableColumn - { - /// - public override string ToString() - { - return $"{Name} ({Type})"; - } - } -} diff --git a/sdk/monitor/Azure.Monitor.Query/tests/LogsQueryClientClientLiveTests.cs b/sdk/monitor/Azure.Monitor.Query/tests/LogsQueryClientClientLiveTests.cs index 78e43309987c..c633c72b608b 100644 --- a/sdk/monitor/Azure.Monitor.Query/tests/LogsQueryClientClientLiveTests.cs +++ b/sdk/monitor/Azure.Monitor.Query/tests/LogsQueryClientClientLiveTests.cs @@ -754,7 +754,7 @@ private record TestModelForTypesNullable public BinaryData Dynamic { get; set; } } - [Test] + [RecordedTest] public async Task ValidateNanAndInfResultsDoubleAsync() { var client = CreateClient(); diff --git a/sdk/monitor/Azure.Monitor.Query/tests/LogsQueryClientTests.cs b/sdk/monitor/Azure.Monitor.Query/tests/LogsQueryClientTests.cs index 229ee87acd44..f06ffe0cb880 100644 --- a/sdk/monitor/Azure.Monitor.Query/tests/LogsQueryClientTests.cs +++ b/sdk/monitor/Azure.Monitor.Query/tests/LogsQueryClientTests.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Azure.Core; @@ -192,5 +193,86 @@ public void MonitorQueryModelFactory_LogsQueryResult_ConvertBinaryDataToJsonElem Assert.AreEqual("PartialError", result.Error.Code); Assert.AreEqual("There were some errors when processing your query.", result.Error.Message); } + + [Test] + public void ValidateMonitorModelFactoryTableCreation() + { + LogsTableColumn logsTableColumn0 = MonitorQueryModelFactory.LogsTableColumn("column0", LogsColumnType.Datetime); + LogsTableColumn logsTableColumn1 = MonitorQueryModelFactory.LogsTableColumn("column1", LogsColumnType.Guid); + LogsTableColumn logsTableColumn2 = MonitorQueryModelFactory.LogsTableColumn("column2", LogsColumnType.Int); + LogsTableColumn logsTableColumn3 = MonitorQueryModelFactory.LogsTableColumn("column3", LogsColumnType.Long); + LogsTableColumn logsTableColumn4 = MonitorQueryModelFactory.LogsTableColumn("column4", LogsColumnType.Real); + LogsTableColumn logsTableColumn5 = MonitorQueryModelFactory.LogsTableColumn("column5", LogsColumnType.String); + LogsTableColumn logsTableColumn6 = MonitorQueryModelFactory.LogsTableColumn("column6", LogsColumnType.Timespan); + LogsTableColumn logsTableColumn7 = MonitorQueryModelFactory.LogsTableColumn("column7", LogsColumnType.Decimal); + LogsTableColumn logsTableColumn8 = MonitorQueryModelFactory.LogsTableColumn("column8", LogsColumnType.Bool); + LogsTableColumn logsTableColumn9 = MonitorQueryModelFactory.LogsTableColumn("column9", LogsColumnType.Dynamic); + LogsTableColumn[] logsTableColumns = new LogsTableColumn[] { logsTableColumn0, logsTableColumn1, logsTableColumn2, logsTableColumn3, logsTableColumn4, logsTableColumn5, logsTableColumn6, logsTableColumn7, logsTableColumn8, logsTableColumn9}; + Object[] rowValues = new Object[] { "2015-12-31T23:59:59.9Z", "74be27de-1e4e-49d9-b579-fe0b331d3642", 12345, 1234567890123, 12345.6789, "string value", "00:00:10", "0.10101", false, "{\u0022a\u0022:123,\u0022b\u0022:\u0022hello\u0022,\u0022c\u0022:[1,2,3],\u0022d\u0022:{}}" }; + + LogsTableRow logsTableRow = MonitorQueryModelFactory.LogsTableRow(logsTableColumns, rowValues); + LogsTableRow[] rowArray = new LogsTableRow[] { logsTableRow }; + LogsTable logsTable = MonitorQueryModelFactory.LogsTable("tester", logsTableColumns.AsEnumerable(), rowArray.AsEnumerable()); + + Assert.AreEqual("tester", logsTable.Name); + Assert.AreEqual(1, logsTable.Rows.Count); + Assert.AreEqual(10, logsTable.Columns.Count); + + Assert.AreEqual("column0", logsTable.Columns[0].Name); + Assert.AreEqual("datetime", logsTable.Columns[0].Type.ToString()); + Assert.AreEqual("column1", logsTable.Columns[1].Name); + Assert.AreEqual("guid", logsTable.Columns[1].Type.ToString()); + Assert.AreEqual("column2", logsTable.Columns[2].Name); + Assert.AreEqual("int", logsTable.Columns[2].Type.ToString()); + Assert.AreEqual("column3", logsTable.Columns[3].Name); + Assert.AreEqual("long", logsTable.Columns[3].Type.ToString()); + Assert.AreEqual("column4", logsTable.Columns[4].Name); + Assert.AreEqual("real", logsTable.Columns[4].Type.ToString()); + Assert.AreEqual("column5", logsTable.Columns[5].Name); + Assert.AreEqual("string", logsTable.Columns[5].Type.ToString()); + Assert.AreEqual("column6", logsTable.Columns[6].Name); + Assert.AreEqual("timespan", logsTable.Columns[6].Type.ToString()); + Assert.AreEqual("column7", logsTable.Columns[7].Name); + Assert.AreEqual("decimal", logsTable.Columns[7].Type.ToString()); + Assert.AreEqual("column8", logsTable.Columns[8].Name); + Assert.AreEqual("bool", logsTable.Columns[8].Type.ToString()); + Assert.AreEqual("column9", logsTable.Columns[9].Name); + Assert.AreEqual("dynamic", logsTable.Columns[9].Type.ToString()); + + var expectedDate = DateTimeOffset.Parse("2015-12-31 23:59:59.9+00:00"); + + Assert.AreEqual(expectedDate, logsTable.Rows[0].GetDateTimeOffset(0)); + Assert.AreEqual(expectedDate, logsTable.Rows[0].GetObject("column0")); + Assert.AreEqual(false, logsTable.Rows[0].GetBoolean("column8")); + Assert.AreEqual(false, logsTable.Rows[0].GetBoolean(8)); + Assert.AreEqual(false, logsTable.Rows[0].GetObject("column8")); + Assert.AreEqual(Guid.Parse("74be27de-1e4e-49d9-b579-fe0b331d3642"), logsTable.Rows[0].GetGuid("column1")); + Assert.AreEqual(Guid.Parse("74be27de-1e4e-49d9-b579-fe0b331d3642"), logsTable.Rows[0].GetGuid(1)); + Assert.AreEqual(Guid.Parse("74be27de-1e4e-49d9-b579-fe0b331d3642"), logsTable.Rows[0].GetObject("column1")); + Assert.AreEqual(12345, logsTable.Rows[0].GetInt32("column2")); + Assert.AreEqual(12345, logsTable.Rows[0].GetInt32(2)); + Assert.AreEqual(12345, logsTable.Rows[0].GetObject("column2")); + Assert.AreEqual(1234567890123, logsTable.Rows[0].GetInt64("column3")); + Assert.AreEqual(1234567890123, logsTable.Rows[0].GetInt64(3)); + Assert.AreEqual(1234567890123, logsTable.Rows[0].GetObject("column3")); + Assert.AreEqual(12345.6789d, logsTable.Rows[0].GetDouble("column4")); + Assert.AreEqual(12345.6789d, logsTable.Rows[0].GetDouble(4)); + Assert.AreEqual(12345.6789d, logsTable.Rows[0].GetObject("column4")); + Assert.AreEqual("string value", logsTable.Rows[0].GetString("column5")); + Assert.AreEqual("string value", logsTable.Rows[0].GetString(5)); + Assert.AreEqual("string value", logsTable.Rows[0].GetObject("column5")); + Assert.AreEqual(TimeSpan.FromSeconds(10), logsTable.Rows[0].GetTimeSpan("column6")); + Assert.AreEqual(TimeSpan.FromSeconds(10), logsTable.Rows[0].GetTimeSpan(6)); + Assert.AreEqual(TimeSpan.FromSeconds(10), logsTable.Rows[0].GetObject("column6")); + Assert.AreEqual(0.10101m, logsTable.Rows[0].GetDecimal("column7")); + Assert.AreEqual(0.10101m, logsTable.Rows[0].GetDecimal(7)); + Assert.AreEqual(0.10101m, logsTable.Rows[0].GetObject("column7")); + Assert.IsFalse(logsTable.Rows[0].GetBoolean("column8")); + Assert.IsFalse(logsTable.Rows[0].GetBoolean(8)); + Assert.AreEqual(false, logsTable.Rows[0].GetObject("column8")); + Assert.AreEqual("{\"a\":123,\"b\":\"hello\",\"c\":[1,2,3],\"d\":{}}", logsTable.Rows[0].GetDynamic(9).ToString()); + Assert.AreEqual("{\"a\":123,\"b\":\"hello\",\"c\":[1,2,3],\"d\":{}}", logsTable.Rows[0].GetDynamic("column9").ToString()); + Assert.AreEqual("{\"a\":123,\"b\":\"hello\",\"c\":[1,2,3],\"d\":{}}", logsTable.Rows[0].GetObject("column9").ToString()); + } } }