Azure Monitor에서 로그 쿼리 시작Get started with log queries in Azure Monitor

참고

하나 이상의 가상 머신에서 데이터를 수집하는 경우 사용자 환경에서 이 연습을 수행할 수 있습니다.You can work through this exercise in your own environment if you are collecting data from at least one virtual machine. 그렇지 않은 경우 다양한 샘플 데이터를 포함하는 데모 환경을 사용합니다.If not then use our Demo environment, which includes plenty of sample data. KQL에서 쿼리하는 방법을 이미 알고 있지만 리소스 유형에 따라 유용한 쿼리를 신속하게 만들어야 하는 경우 저장된 예제 쿼리 창을 참조하세요.If you already know how to query in KQL, but just need to quickly create useful queries based on resource type(s), see the saved example queries pane.

이 자습서에서는 Azure Monitor에서 로그 쿼리를 작성하는 방법을 배웁니다.In this tutorial you will learn to write log queries in Azure Monitor. 다음을 수행하는 방법에 대해 알아봅니다.It will teach you how to:

  • 쿼리 구조 이해Understand query structure
  • 쿼리 결과 정렬Sort query results
  • 쿼리 결과 필터링Filter query results
  • 시간 범위 지정Specify a time range
  • 결과에 포함할 필드 선택Select which fields to include in the results
  • 사용자 지정 필드 정의 및 사용Define and use custom fields
  • 결과 집계 및 그룹화Aggregate and group results

Azure Portal에서 Log Analytics를 사용하는 방법에 대한 자습서는 Azure Monitor Log Analytics 시작을 참조하세요.For a tutorial on using Log Analytics in the Azure portal, see Get started with Azure Monitor Log Analytics.
Azure Monitor에서 로그 쿼리에 대한 자세한 내용은 Azure Monitor에서 로그 쿼리 개요를 참조하세요.For more details on log queries in Azure Monitor, see Overview of log queries in Azure Monitor.

아래 자습서의 비디오 버전을 따르세요.Follow along with a video version of this tutorial below:

새 쿼리 작성Writing a new query

쿼리는 테이블 이름 또는 search 명령을 사용하여 시작할 수 있습니다.Queries can start with either a table name or the search command. 쿼리에 대한 명확한 범위를 정의하고 쿼리 성능 및 결과의 관련성을 개선하므로 테이블 이름을 사용하여 시작해야 합니다.You should start with a table name, since it defines a clear scope for the query and improves both query performance and relevance of the results.

참고

Azure Monitor에서 사용되는 Kusto 쿼리 언어는 대/소문자를 구분합니다.The Kusto query language used by Azure Monitor is case-sensitive. 언어 키워드는 일반적으로 소문자로 작성됩니다.Language keywords are typically written in lower-case. 쿼리에서 테이블 또는 열 이름을 사용하는 경우 스키마 창에 표시된 대로 정확한 대/소문자를 사용해야 합니다.When using names of tables or columns in a query, make sure to use the correct case, as shown on the schema pane.

테이블 기반 쿼리Table-based queries

Azure Monitor는 테이블에 각각 여러 열로 구성된 로그 데이터를 구성합니다.Azure Monitor organizes log data in tables, each composed of multiple columns. 모든 테이블 및 열은 Analytics 포털에서 Log Analytics의 스키마 창에 표시됩니다.All tables and columns are shown on the schema pane in Log Analytics in the Analytics portal. 관심 있는 테이블을 식별한 다음, 일부 데이터를 살펴봅니다.Identify a table that you're interested in and then take a look at a bit of data:

SecurityEvent
| take 10

위에 표시된 쿼리는 특정 순서 없이 SecurityEvent 테이블에서 10개의 결과를 반환합니다.The query shown above returns 10 results from the SecurityEvent table, in no specific order. 이는 테이블을 살펴보고 해당 구조 및 콘텐츠를 이해하는 매우 일반적인 방법입니다.This is a very common way to take a glance at a table and understand its structure and content. 빌드되는 방식을 살펴보겠습니다.Let's examine how it's built:

  • 쿼리는 테이블 이름 SecurityEvent 로 시작합니다. 이 일부는 쿼리의 범위를 정의합니다.The query starts with the table name SecurityEvent - this part defines the scope of the query.
  • 파이프(|) 문자는 명령을 분리하므로 다음 명령의 입력에서 첫 번째 명령의 출력입니다.The pipe (|) character separates commands, so the output of the first one in the input of the following command. 임의의 수의 파이프된 요소를 추가할 수 있습니다.You can add any number of piped elements.
  • 다음 파이프는 테이블에서 특정 개수의 임의 레코드를 반환하는 take 명령입니다.Following the pipe is the take command, which returns a specific number of arbitrary records from the table.

| take 10을 추가하지 않고도 실제로 쿼리를 실행할 수 있습니다. 이는 여전히 유효할 수 있지만 최대 10,000개의 결과를 반환할 수 있습니다.We could actually run the query even without adding | take 10 - that would still be valid, but it could return up to 10,000 results.

검색 쿼리Search queries

검색 쿼리는 덜 구조적이며, 일반적으로 해당 열에 있는 특정 값을 포함하는 레코드를 찾기에 더 적합합니다.Search queries are less structured, and generally more suited for finding records that include a specific value in any of their columns:

search in (SecurityEvent) "Cryptographic"
| take 10

이 쿼리는 구문 "Cryptographic"을 포함하는 레코드에 대한 SecurityEvent 테이블을 검색합니다.This query searches the SecurityEvent table for records that contain the phrase "Cryptographic". 이러한 레코드 중 10개의 레코드가 반환되고 표시됩니다.Of those records, 10 records will be returned and displayed. in (SecurityEvent) 부분을 생략하고 search "Cryptographic"만을 실행하는 경우 검색은 모든 테이블을 살펴봅니다. 이는 시간이 더 걸리며 덜 효율적입니다.If we omit the in (SecurityEvent) part and just run search "Cryptographic", the search will go over all tables, which would take longer and be less efficient.

경고

검색 쿼리는 더 많은 데이터를 처리해야 하기 때문에 일반적으로 테이블 기반 쿼리보다 느립니다.Search queries are typically slower than table-based queries because they have to process more data.

정렬 및 위쪽Sort and top

take 가 몇 가지 레코드를 가져오는 데 유용하지만 특정 순서 없이 결과가 선택되고 표시됩니다.While take is useful to get a few records, the results are selected and displayed in no particular order. 정렬된 보기를 가져오려면 기본 열을 기준으로 정렬 할 수 있습니다.To get an ordered view, you could sort by the preferred column:

SecurityEvent   
| sort by TimeGenerated desc

그러나 너무 많은 결과를 반환할 수 있으며 약간의 시간이 소요될 수 있습니다.That could return too many results though and might also take some time. 위의 쿼리는 TimeGenerated 열을 기준으로 전체 SecurityEvent 테이블을 정렬합니다.The above query sorts the entire SecurityEvent table by the TimeGenerated column. 그런 다음, Analytics 포털은 10,000개의 레코드만을 표시하도록 디스플레이를 제한합니다.The Analytics portal then limits the display to show only 10,000 records. 이 방법은 물론 최적이 아닙니다.This approach is of course not optimal.

최신 10개의 레코드만을 가져오는 가장 좋은 방법은 서버 쪽에서 전체 테이블을 정렬한 다음, 상위 레코드를 반환하는 top 을 사용하는 것입니다.The best way to get only the latest 10 records is to use top, which sorts the entire table on the server side and then returns the top records:

SecurityEvent
| top 10 by TimeGenerated

내림차순은 기본 정렬 순서이므로 일반적으로 desc 인수를 생략합니다. 출력은 다음과 같습니다.Descending is the default sorting order, so we typically omit the desc argument.The output will look like this:

상위 10개

Where: 조건에 대한 필터링Where: filtering on a condition

해당 이름으로 표시된 대로 Filters, 특정 조건에 따라 데이터를 필터링합니다.Filters, as indicated by their name, filter the data by a specific condition. 이는 관련 정보에 대한 쿼리 결과를 제한하는 가장 일반적인 방법입니다.This is the most common way to limit query results to relevant information.

쿼리에 필터를 추가하려면 하나 이상의 조건이 뒤에 오는 where 연산자를 사용합니다.To add a filter to a query, use the where operator followed by one or more conditions. 예를 들어 다음 쿼리는 Level8SecurityEvent 레코드만을 반환합니다.For example, the following query returns only SecurityEvent records where Level equals 8:

SecurityEvent
| where Level == 8

필터 조건을 작성하는 경우 다음 식을 사용할 수 있습니다.When writing filter conditions, you can use the following expressions:

Expression DescriptionDescription 예제Example
== 같은지 여부를 확인Check equality
(대/소문자 구분)(case-sensitive)
Level == 8
=~ 같은지 여부를 확인Check equality
(대/소문자 구분하지 않음)(case-insensitive)
EventSourceName =~ "microsoft-windows-security-auditing"
!=, <>!=, <> 같지 않음 확인Check inequality
(두 식이 모두 동일)(both expressions are identical)
Level != 4
and, orand, or between 조건 필수Required between conditions Level == 16 or CommandLine != ""

여러 조건으로 필터링하려면 and 를 사용하거나To filter by multiple conditions, you can either use and:

SecurityEvent
| where Level == 8 and EventID == 4672

여러 where 요소를 번갈아 파이프할 수 있습니다.or pipe multiple where elements one after the other:

SecurityEvent
| where Level == 8 
| where EventID == 4672

참고

값은 여러 형식을 가질 수 있으므로 올바른 형식에서 비교를 수행하도록 캐스트해야 할 수 있습니다.Values can have different types, so you might need to cast them to perform comparison on the correct type. 예를 들어 SecurityEvent Level 열이 String 형식이므로 숫자 연산자를 사용하기 전에 int 또는 long 과 같은 숫자 형식으로 캐스트해야 합니다. SecurityEvent | where toint(Level) >= 10For example, SecurityEvent Level column is of type String, so you must cast it to a numerical type such as int or long, before you can use numerical operators on it: SecurityEvent | where toint(Level) >= 10

시간 범위 지정Specify a time range

시간 선택기Time picker

시간 선택기는 실행 단추 옆에 있고 지난 24시간의 레코드만을 쿼리하는 것을 나타냅니다.The time picker is next to the Run button and indicates we’re querying only records from the last 24 hours. 이는 모든 쿼리에 적용되는 기본 시간 범위입니다.This is the default time range applied to all queries. 지난 1시간의 레코드만을 가져오려면 지난 1시간 을 선택하고 쿼리를 다시 실행합니다.To get only records from the last hour, select Last hour and run the query again.

시간 선택

쿼리에서 시간 필터Time filter in query

쿼리에 시간 필터를 추가하여 고유한 시간 범위를 정의할 수도 있습니다.You can also define your own time range by adding a time filter to the query. 시간 필터를 테이블 이름 바로 뒤에 배치하는 것이 좋습니다.It’s best to place the time filter immediately after the table name:

SecurityEvent
| where TimeGenerated > ago(30m) 
| where toint(Level) >= 10

위의 시간 필터에서 ago(30m)는 "30분 전"을 의미하므로 이 쿼리는 최근 30분의 레코드만을 반환합니다.In the above time filter ago(30m) means "30 minutes ago" so this query only returns records from the last 30 minutes. 기타 시간 단위에는 일(2d), 분(25m) 및 초(10s)가 포함됩니다.Other units of time include days (2d), minutes (25m), and seconds (10s).

Project 및 Extend: 열 선택 및 컴퓨팅Project and Extend: select and compute columns

project 를 사용하여 결과에 포함할 특정 열을 선택합니다.Use project to select specific columns to include in the results:

SecurityEvent 
| top 10 by TimeGenerated 
| project TimeGenerated, Computer, Activity

앞의 예제에서는 이 출력을 생성합니다.The preceding example generates this output:

쿼리 프로젝트 결과

project 를 사용하여 열 이름을 바꾸고 새 열을 정의할 수도 있습니다.You can also use project to rename columns and define new ones. 다음 예제에서는 project를 사용하여 다음을 수행합니다.The following example uses project to do the following:

  • ComputerTimeGenerated 원본 열만을 선택합니다.Select only the Computer and TimeGenerated original columns.
  • Activity 열을 EventDetails 로 표시합니다.Displays the Activity column as EventDetails.
  • EventCode 라는 새 열을 만듭니다.Create a new column named EventCode. substring() 함수는 Activity 필드에서 첫 번째 네 개의 문자만을 가져오는 데 사용됩니다.The substring() function is used to get only the first four characters from the Activity field.
SecurityEvent
| top 10 by TimeGenerated 
| project Computer, TimeGenerated, EventDetails=Activity, EventCode=substring(Activity, 0, 4)

extend 는 결과 집합에서 모든 원본 열을 유지하고 추가 항목을 정의합니다.extend keeps all original columns in the result set and defines additional ones. 다음 쿼리에서는 확장 을 사용하여 EventCode 열을 추가합니다.The following query uses extend to add the EventCode column. 이 열은 테이블의 끝에 표시되지 않을 수 있으며, 이 경우 레코드의 세부 정보를 확장해야 합니다.Note that this column may not display at the end of the table results in which case you would need to expand the details of a record to view it.

SecurityEvent
| top 10 by TimeGenerated
| extend EventCode=substring(Activity, 0, 4)

Summarize: 행 그룹 집계Summarize: aggregate groups of rows

summarize 를 사용하여 하나 이상의 열에 따라 레코드 그룹을 식별하고, 집계를 적용합니다.Use summarize to identify groups of records, according to one or more columns, and apply aggregations to them. summarize 의 가장 일반적인 사용은 count 이며 각 그룹의 결과 수를 반환합니다.The most common use of summarize is count, which returns the number of results in each group.

다음 쿼리는 지난 시간에서 모든 Perf 레코드를 검토하고, ObjectName 으로 그룹화하고, 각 그룹의 레코드 수를 계산합니다.The following query reviews all Perf records from the last hour, groups them by ObjectName, and counts the records in each group:

Perf
| where TimeGenerated > ago(1h)
| summarize count() by ObjectName

경우에 따라 여러 차원에서 그룹을 정의하는 것일 수 있습니다.Sometimes it makes sense to define groups by multiple dimensions. 이러한 값의 각 고유한 조합은 별도 그룹을 정의합니다.Each unique combination of these values defines a separate group:

Perf
| where TimeGenerated > ago(1h)
| summarize count() by ObjectName, CounterName

또 다른 일반적인 사용은 각 그룹에 대해 수치 연산 또는 통계 계산을 수행하는 것입니다.Another common use is to perform mathematical or statistical calculations on each group. 예를 들어 다음은 각 컴퓨터에 대한 평균 CounterValue 를 계산합니다.For example, the following calculates the average CounterValue for each computer:

Perf
| where TimeGenerated > ago(1h)
| summarize avg(CounterValue) by Computer

그러나 여기서 다양한 성능 카운터를 함께 혼합했으므로 이 쿼리의 결과는 의미가 없습니다.Unfortunately, the results of this query are meaningless since we mixed together different performance counters. 더욱 의미 있게 하기 위해 CounterNameComputer 의 각 조합에 대해 개별적으로 평균을 계산해야 합니다.To make this more meaningful, we should calculate the average separately for each combination of CounterName and Computer:

Perf
| where TimeGenerated > ago(1h)
| summarize avg(CounterValue) by Computer, CounterName

시간 열별 요약Summarize by a time column

결과 그룹화는 time 열 또는 다른 연속 값을 기준으로 할 수도 있습니다.Grouping results can also be based on a time column, or another continuous value. 그러나 간단히 by TimeGenerated를 요약하면 이는 고유한 값이므로 시간 범위 동안 모든 단일 밀리초에 대한 그룹을 만듭니다.Simply summarizing by TimeGenerated though would create groups for every single millisecond over the time range, since these are unique values.

연속 값에 따라 그룹을 만들려면 bin 을 사용하여 범위를 관리 가능한 단위로 나누는 것이 가장 좋습니다.To create groups based on continuous values, it is best to break the range into manageable units using bin. 다음 쿼리는 특정 컴퓨터에서 사용 가능한 메모리(Available MBytes)를 측정하는 Perf 레코드를 분석합니다.The following query analyzes Perf records that measure free memory (Available MBytes) on a specific computer. 지난 7일 동안 각 1시간의 평균 값을 계산합니다.It calculates the average value of each 1 hour period over the last 7 days:

Perf 
| where TimeGenerated > ago(7d)
| where Computer == "ContosoAzADDS2" 
| where CounterName == "Available MBytes" 
| summarize avg(CounterValue) by bin(TimeGenerated, 1h)

출력을 명확히 하려면 시간에 따른 사용 가능한 메모리를 보여주는 시간 차트로 표시하도록 선택합니다.To make the output clearer, you select to display it as a time-chart, showing the available memory over time:

시간에 따른 쿼리 메모리

다음 단계Next steps