diff --git a/sdk/monitor/azure-monitor-query/migration-guide-query-logs.md b/sdk/monitor/azure-monitor-query/migration-guide-query-logs.md new file mode 100644 index 000000000000..c288dc464ca0 --- /dev/null +++ b/sdk/monitor/azure-monitor-query/migration-guide-query-logs.md @@ -0,0 +1,415 @@ +# Guide for migrating from `azure-monitor-query` to `azure-monitor-query-logs` + +This guide assists in migrating querying logs operations in `azure-monitor-query` to the dedicated `azure-monitor-query-logs` library. + +## Table of contents + +- [Migration benefits](#migration-benefits) +- [Important changes](#important-changes) + - [Group ID, artifact ID, and package names](#group-id-artifact-id-and-package-names) + - [Client differences](#client-differences) + - [API changes](#api-changes) + - [Instantiate logs query clients](#instantiate-logs-query-clients) + - [Query logs from workspace](#query-logs-from-workspace) + - [Query resource logs](#query-resource-logs) +- [Additional samples](#additional-samples) + +## Migration benefits + +The Azure Monitor Query library for Java has been modularized to provide more focused functionality. The operations for querying logs have been moved from the combined `azure-monitor-query` package which also included querying metrics to a dedicated `azure-monitor-query-logs` package. This separation offers several advantages: + +- Smaller dependency footprint for applications that only need to query logs +- More focused API design specific to logs query operations +- Independent versioning allowing logs functionality to evolve separately +- Clearer separation of concerns between logs and metrics operations + +## Important changes + +### Group ID, artifact ID, and package names + +Both libraries have the same group ID (`com.azure`), but the artifact ID and package names have changed: + +- Previous artifact ID: `azure-monitor-query` +- New artifact ID: `azure-monitor-query-logs` + +- Previous package for logs query clients: `com.azure.monitor.query` +- New package: `com.azure.monitor.query.logs` + +**Maven dependency changes:** + +Previous dependency in `pom.xml`: +```xml + + com.azure + azure-monitor-query + 1.x.x + +``` + +New dependency in `pom.xml`: +```xml + + com.azure + azure-monitor-query-logs + 1.x.x + +``` + +### Client differences + +`LogsQueryClient` and `LogsQueryAsyncClient` classes are in `com.azure.monitor.query` package in `azure-monitor-query` library. These clients have been +moved to `com.azure.monitor.query.logs` package in the new `azure-monitor-query-logs` library. The client names and the client builder name remains the same in both libraries. + +### API changes + +The following API changes were made between `azure-monitor-query` and `azure-monitor-query-logs`: + +| `azure-monitor-query` | `azure-monitor-query-logs` | Notes | +|------------------------|-------------------------------------------------------------|-------------------------------------------------| +| `com.azure.monitor.query.models.QueryTimeInterval` | `com.azure.monitor.query.logs.models.LogsQueryTimeInterval` | Used to specify the time range for logs queries | + +Code using the previous `QueryTimeInterval` class will need to be updated to use the new `LogsQueryTimeInterval` class: + +Previous code: +```java +import com.azure.monitor.query.models.QueryTimeInterval; +import java.time.OffsetDateTime; + +public class QueryTimeIntervalSample { + public static void main(String[] args) { + // Create a time interval with explicit start and end times + OffsetDateTime endTime = OffsetDateTime.now(); + OffsetDateTime startTime = endTime.minusHours(24); + QueryTimeInterval timeInterval = new QueryTimeInterval(startTime, endTime); + + System.out.println("Time interval created from " + timeInterval.getStartTime() + + " to " + timeInterval.getEndTime()); + } +} +``` + +New code: +```java +import com.azure.monitor.query.logs.models.LogsQueryTimeInterval; +import java.time.OffsetDateTime; + +public class LogsQueryTimeIntervalSample { + public static void main(String[] args) { + // Create a time interval with explicit start and end times + OffsetDateTime endTime = OffsetDateTime.now(); + OffsetDateTime startTime = endTime.minusHours(24); + LogsQueryTimeInterval timeInterval = new LogsQueryTimeInterval(startTime, endTime); + + System.out.println("Time interval created from " + timeInterval.getStartTime() + + " to " + timeInterval.getEndTime()); + } +} +``` + +### Instantiate logs query clients + +In `azure-monitor-query`, logs functionality was accessed through the `LogsQueryClient` and `LogsQueryAsyncClient` classes: + +```java +import com.azure.monitor.query.LogsQueryClient; +import com.azure.monitor.query.LogsQueryClientBuilder; +import com.azure.monitor.query.LogsQueryAsyncClient; +import com.azure.identity.DefaultAzureCredentialBuilder; +import com.azure.core.credential.TokenCredential; + +public class LogsQueryClientSample { + public static void main(String[] args) { + TokenCredential tokenCredential = new DefaultAzureCredentialBuilder().build(); + + // Create synchronous client + LogsQueryClient logsQueryClient = new LogsQueryClientBuilder() + .credential(tokenCredential) + .buildClient(); + + // Create asynchronous client + LogsQueryAsyncClient logsQueryAsyncClient = new LogsQueryClientBuilder() + .credential(tokenCredential) + .buildAsyncClient(); + + System.out.println("Successfully created logs query client"); + } +} +``` + +In `azure-monitor-query-logs`, the class names remain the same but the package names used in import statements should be updated to `com.azure.monitor.query.logs.*`: + +```java +import com.azure.monitor.query.logs.LogsQueryClient; +import com.azure.monitor.query.logs.LogsQueryClientBuilder; +import com.azure.monitor.query.logs.LogsQueryAsyncClient; +import com.azure.identity.DefaultAzureCredentialBuilder; +import com.azure.core.credential.TokenCredential; + +public class LogsQueryClientSample { + public static void main(String[] args) { + TokenCredential tokenCredential = new DefaultAzureCredentialBuilder().build(); + + // Create synchronous client + LogsQueryClient logsQueryClient = new LogsQueryClientBuilder() + .credential(tokenCredential) + .buildClient(); + + // Create asynchronous client + LogsQueryAsyncClient logsQueryAsyncClient = new LogsQueryClientBuilder() + .credential(tokenCredential) + .buildAsyncClient(); + + System.out.println("Successfully created logs query client"); + } +} +``` + +### Query logs from workspace + +The method signatures for querying logs remain largely the same, but you'll need to update the import statements: + +Previous code: +```java +import com.azure.monitor.query.LogsQueryClient; +import com.azure.monitor.query.LogsQueryClientBuilder; +import com.azure.monitor.query.LogsQueryAsyncClient; +import com.azure.monitor.query.models.LogsQueryResult; +import com.azure.monitor.query.models.LogsTable; +import com.azure.monitor.query.models.LogsTableCell; +import com.azure.monitor.query.models.LogsTableRow; +import com.azure.identity.DefaultAzureCredentialBuilder; +import com.azure.core.credential.TokenCredential; + +import java.util.Optional; + +public class LogsQuerySample { + public static void main(String[] args) { + TokenCredential tokenCredential = new DefaultAzureCredentialBuilder().build(); + + LogsQueryClient logsQueryClient = new LogsQueryClientBuilder() + .credential(tokenCredential) + .buildClient(); + + LogsQueryResult queryResults = logsQueryClient.queryWorkspace("", "AppRequests", + null); + System.out.println("Number of tables = " + queryResults.getAllTables().size()); + + // Sample to iterate over all cells in the table + for (LogsTable table : queryResults.getAllTables()) { + for (LogsTableCell tableCell : table.getAllTableCells()) { + System.out.println("Column = " + tableCell.getColumnName() + "; value = " + tableCell.getValueAsString()); + } + } + + // Sample to iterate by row + for (LogsTable table : queryResults.getAllTables()) { + for (LogsTableRow row : table.getRows()) { + row.getRow() + .forEach(cell -> System.out.println("Column = " + cell.getColumnName() + "; value = " + cell.getValueAsString())); + } + } + + // Sample to get value of a column + for (LogsTable table : queryResults.getAllTables()) { + for (LogsTableRow row : table.getRows()) { + Optional resourceGroup = row.getColumnValue("DurationMs"); + if (resourceGroup.isPresent()) { + System.out.println(resourceGroup.get().getValueAsString()); + } + } + } + } +} +``` + +New code: +```java +import com.azure.monitor.query.logs.LogsQueryClient; +import com.azure.monitor.query.logs.LogsQueryClientBuilder; +import com.azure.monitor.query.logs.LogsQueryAsyncClient; +import com.azure.monitor.query.logs.models.LogsQueryResult; +import com.azure.monitor.query.logs.models.LogsTable; +import com.azure.monitor.query.logs.models.LogsTableCell; +import com.azure.monitor.query.logs.models.LogsTableRow; +import com.azure.identity.DefaultAzureCredentialBuilder; +import com.azure.core.credential.TokenCredential; + +import java.util.Optional; + +public class LogsQuerySample { + public static void main(String[] args) { + TokenCredential tokenCredential = new DefaultAzureCredentialBuilder().build(); + + LogsQueryClient logsQueryClient = new LogsQueryClientBuilder() + .credential(tokenCredential) + .buildClient(); + + LogsQueryResult queryResults = logsQueryClient.queryWorkspace("", "AppRequests", + null); + System.out.println("Number of tables = " + queryResults.getAllTables().size()); + + // Sample to iterate over all cells in the table + for (LogsTable table : queryResults.getAllTables()) { + for (LogsTableCell tableCell : table.getAllTableCells()) { + System.out.println("Column = " + tableCell.getColumnName() + "; value = " + tableCell.getValueAsString()); + } + } + + // Sample to iterate by row + for (LogsTable table : queryResults.getAllTables()) { + for (LogsTableRow row : table.getRows()) { + row.getRow() + .forEach(cell -> System.out.println("Column = " + cell.getColumnName() + "; value = " + cell.getValueAsString())); + } + } + + // Sample to get value of a column + for (LogsTable table : queryResults.getAllTables()) { + for (LogsTableRow row : table.getRows()) { + Optional resourceGroup = row.getColumnValue("DurationMs"); + if (resourceGroup.isPresent()) { + System.out.println(resourceGroup.get().getValueAsString()); + } + } + } + } +} +``` +### Query resource logs + +Previous code: + +```java +import com.azure.core.credential.TokenCredential; +import com.azure.identity.DefaultAzureCredentialBuilder; +import com.azure.monitor.query.LogsQueryClient; +import com.azure.monitor.query.LogsQueryClientBuilder; +import com.azure.monitor.query.LogsQueryAsyncClient; +import com.azure.monitor.query.models.LogsQueryResult; +import com.azure.monitor.query.models.LogsTable; +import com.azure.monitor.query.models.LogsTableCell; +import com.azure.monitor.query.models.LogsTableRow; +import com.azure.monitor.query.models.QueryTimeInterval; + +import java.util.Optional; + +/** + * A sample to demonstrate querying for logs of an Azure resource from Azure Monitor using a Kusto query + */ +public class LogsQueryResourceSample { + + /** + * The main method to execute the sample. + * @param args Ignored args. + */ + public static void main(String[] args) { + TokenCredential tokenCredential = new DefaultAzureCredentialBuilder().build(); + + LogsQueryClient logsQueryClient = new LogsQueryClientBuilder() + .credential(tokenCredential) + .buildClient(); + + LogsQueryResult queryResults = logsQueryClient + .queryResource("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}", "AppRequests", + QueryTimeInterval.ALL); + System.out.println("Number of tables = " + queryResults.getAllTables().size()); + + // Sample to iterate over all cells in the table + for (LogsTable table : queryResults.getAllTables()) { + for (LogsTableCell tableCell : table.getAllTableCells()) { + System.out.println("Column = " + tableCell.getColumnName() + "; value = " + tableCell.getValueAsString()); + } + } + + // Sample to iterate by row + for (LogsTable table : queryResults.getAllTables()) { + for (LogsTableRow row : table.getRows()) { + row.getRow() + .forEach(cell -> System.out.println("Column = " + cell.getColumnName() + "; value = " + cell.getValueAsString())); + } + } + + // Sample to get value of a column + for (LogsTable table : queryResults.getAllTables()) { + for (LogsTableRow row : table.getRows()) { + Optional resourceGroup = row.getColumnValue("DurationMs"); + if (resourceGroup.isPresent()) { + System.out.println(resourceGroup.get().getValueAsString()); + } + } + } + } +} +``` + +New code: + +```java +import com.azure.core.credential.TokenCredential; +import com.azure.identity.DefaultAzureCredentialBuilder; +import com.azure.monitor.query.logs.LogsQueryClient; +import com.azure.monitor.query.logs.LogsQueryClientBuilder; +import com.azure.monitor.query.logs.LogsQueryAsyncClient; +import com.azure.monitor.query.logs.models.LogsQueryResult; +import com.azure.monitor.query.logs.models.LogsTable; +import com.azure.monitor.query.logs.models.LogsTableCell; +import com.azure.monitor.query.logs.models.LogsTableRow; +import com.azure.monitor.query.logs.models.LogsQueryTimeInterval; + +import java.util.Optional; + +/** + * A sample to demonstrate querying for logs of an Azure resource from Azure Monitor using a Kusto query + */ +public class LogsQueryResourceSample { + + /** + * The main method to execute the sample. + * @param args Ignored args. + */ + public static void main(String[] args) { + TokenCredential tokenCredential = new DefaultAzureCredentialBuilder().build(); + + LogsQueryClient logsQueryClient = new LogsQueryClientBuilder() + .credential(tokenCredential) + .buildClient(); + + LogsQueryResult queryResults = logsQueryClient + .queryResource("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}", "AppRequests", + LogsQueryTimeInterval.ALL); + System.out.println("Number of tables = " + queryResults.getAllTables().size()); + + // Sample to iterate over all cells in the table + for (LogsTable table : queryResults.getAllTables()) { + for (LogsTableCell tableCell : table.getAllTableCells()) { + System.out.println("Column = " + tableCell.getColumnName() + "; value = " + tableCell.getValueAsString()); + } + } + + // Sample to iterate by row + for (LogsTable table : queryResults.getAllTables()) { + for (LogsTableRow row : table.getRows()) { + row.getRow() + .forEach(cell -> System.out.println("Column = " + cell.getColumnName() + "; value = " + cell.getValueAsString())); + } + } + + // Sample to get value of a column + for (LogsTable table : queryResults.getAllTables()) { + for (LogsTableRow row : table.getRows()) { + Optional resourceGroup = row.getColumnValue("DurationMs"); + if (resourceGroup.isPresent()) { + System.out.println(resourceGroup.get().getValueAsString()); + } + } + } + } +} +``` + +## Additional samples + +More examples can be found in the [Azure Monitor Query Logs samples][logs-samples]. + + +[logs-samples]: https://github.com/Azure/azure-sdk-for-java/blob/main/sdk/monitor/azure-monitor-query-logs/src/samples/README.md