MongoDB에 모든 쿼리 기록

Tahseen Tauseef 2023년6월20일
  1. MongoDB의 getLog 명령
  2. MongoDB에서 쿼리를 로깅하기 위한 상세 수준
  3. MongoDB에서 느린 작업 기록
  4. mongosh 내의 로그 쿼리 결과 필터링
  5. jq를 사용하여 mongosh 외부의 로그 쿼리 결과 필터링
MongoDB에 모든 쿼리 기록

이 기사에서는 MongoDB에서 쿼리를 로깅하는 방법에 대해 알아봅니다. 또한 MongoDB에서 쿼리를 로깅하는 데 사용되는 연산자에 대해 자세히 설명합니다.

MongoDB의 getLog 명령

관리자 명령 getLog는 가장 최근에 기록된 mongod 항목 1024개를 검색합니다. getLog 명령은 mongod 로그 파일에서 로그 데이터를 검색하지 않습니다. 대신 기록된 mongod 이벤트의 RAM 캐시에서 정보를 가져옵니다.

db.adminCommand() 함수를 사용하여 getLog를 실행합니다. getLog는 MongoDB 4.4부터 이스케이프된 Relaxed Extended JSON v2.0 형식으로 로그 데이터를 제공합니다. 로그 데이터는 이전에 일반 텍스트로 전달되었습니다.

getLog 명령의 구문은 다음과 같습니다.

db.adminCommand( { getLog: <value> } )

getLog에 가능한 값은 다음과 같습니다.

설명
* getLog 명령에 사용 가능한 값 목록을 반환합니다.
global 모든 로그 항목의 결합된 출력을 반환합니다.
startupwarnings 현재 프로세스가 시작된 시점의 오류 또는 경고를 포함할 수 있는 MongoDB 로그의 로그 항목을 반환합니다. mongod가 기호 없이 시작된 경우 이 필터는 빈 배열을 반환할 수 있습니다.

*가 제공되면 명령은 다른 유효한 값의 이름이 포함된 문서를 반환합니다. 그렇지 않으면 이 명령은 다음 필드가 있는 문서를 생성합니다.

  1. 로그 이벤트의 수를 포함하는 totalLinesWritten 필드
  2. 로그 이벤트의 배열을 포함하는 log 필드;
  3. db.adminCommand()의 상태 및 타임스탬프 정보를 제공하는 응답 문서.

MongoDB에서 getLog 명령의 줄 자르기 동작

MongoDB 4.2부터 getLog는 1024자를 초과하는 모든 이벤트를 자릅니다. 이전 버전에서는 512자 이후에 잘립니다.

MongoDB에서 getLog 명령의 문자 회피 동작

MongoDB 4.4부터 getLog는 로그 출력을 유효한 JSON으로 변환하기 위해 아래 나열된 이스케이프 시퀀스를 활용하여 이스케이프된 Relaxed Extended JSON v2.0 형식으로 로그 데이터를 제공합니다.

대표 캐릭터 이스케이프 시퀀스
백슬래시(\) \\
인용 부호(") \"
용지 공급(0x0C) \f
백스페이스(0x08) \b
캐리지 리턴(0x0D) \r
가로 탭(0x09) \t
개행(0x0A) \n

위에 언급되지 않은 제어 문자는 uXXXX,로 이스케이프됩니다. 여기서 XXXX는 유니코드 코드 포인트에 대한 16진수 코드 포인트입니다. UTF-8 인코딩이 잘못된 바이트는 ufffd 유니코드 대체 문자로 대체됩니다.

MongoDB에서 쿼리를 로깅하기 위한 상세 수준

MongoDB에서 생성되는 로그 메시지의 수를 늘리거나 줄이기 위해 로깅 상세 수준을 변경할 수 있습니다. 자세한 정도는 모든 구성 요소에 대해 집합적으로 수정하거나 식별된 구성 요소를 개별적으로 수정할 수 있습니다.

심각도 범주 정보 및 디버그의 로그 항목만 세부 정보 표시의 영향을 받습니다. 이 수준 위에는 심각도 범주가 항상 표시됩니다.

디버깅 또는 개발 중 광범위한 로깅을 위해 자세한 정보 표시 설정을 높은 값으로 설정하거나 검증된 프로덕션 배포에서 로그 쓰기를 제한하려면 낮은 값으로 설정합니다.

MongoDB에서 현재 로그 상세도 수준 검사

db.getLogComponents() 함수를 사용하여 현재 상세 수준을 확인합니다.

db.getLogComponents()

출력은 다음과 유사할 수 있습니다.

MongoDB 로그 쿼리 - 결과

첫 번째 항목 상세 정보는 모든 구성 요소에 대한 전역 상세 수준입니다. accessControl,과 같이 이후에 이름이 지정된 구성 요소는 해당 구성 요소의 특정 상세 수준을 나타내며 설정된 경우 전역 상세 수준을 재정의합니다.

-1 값은 구성 요소가 전역 상세 수준 중 하나가 있는 경우 부모의 상세 수준을 상속함을 보여줍니다(command와 같이).

MongoDB에서 로그 자세한 정도 수준 구성

systemLog.verbositysystemLog.component.name>.verbositylogComponentVerbosity 인수를 설정하며 db.setLogLevel() 함수는 모두 자세한 정도를 변경하는 데 사용될 수 있습니다.

systemLog 세부 정보 표시 설정을 사용하여 레벨 제어

systemLog.verbosity 매개변수를 사용하여 모든 구성 요소에 대한 기본 로그 수준을 지정합니다. systemLog.component.name>.verbosity 설정을 사용하여 특정 구성 요소의 수준을 제어합니다.

예를 들어, 다음 구성은 systemLog.verbosity1로 설정하며, systemLog.component.query.verbosity2로, systemLog.component.storage.verbosity2로, 그리고 systemLog.component.storage.journal.verbosity1로 설정합니다:

systemLog:
   verbosity: 1
   component:
      query:
         verbosity: 2
      storage:
         verbosity: 2
         journal:
            verbosity: 1

mongod 또는 mongos 인스턴스의 경우 구성 파일 또는 명령줄에서 이러한 설정을 지정합니다.

구성에 명시적으로 지정되지 않은 모든 구성 요소의 상세 수준은 -1입니다. 전역 상세 수준 중 하나가 있는 경우 부모의 상세 수준을 사용함을 나타냅니다.

logComponentVerbosity 매개변수 변경

logComponentVerbosity 옵션을 변경하려면 상세 설정이 포함된 문서를 전달하십시오.

예를 들어 다음 명령은 기본 상세 수준을 2로, query3으로, storage4로, storage.journal1로 변경합니다.

db.adminCommand( {
   setParameter: 1,
   logComponentVerbosity: {
      verbosity: 2,
      query: {
         verbosity: 3
      },
      storage: {
         verbosity: 4,
         journal: {
            verbosity: 1
         }
      }
   }
} )

mongosh.에서 이러한 값을 설정할 수 있습니다.

db.setLogLevel()을 사용하여 MongoDB에서 로그 수준 변경

단일 구성 요소의 로그 수준을 변경하려면 db.setLogLevel() 함수를 사용하십시오. 구성 요소에 대해 0에서 5의 상세 수준을 정의하거나 -1을 지정하여 상위의 상세 수준을 상속할 수 있습니다.

예를 들어 systemLog.component.query.verbosity를 상위 상세도(즉, 기본 상세도)로 설정하는 것은 다음과 같습니다.

db.setLogLevel(-1, "query")

mongosh.에서 이 값을 설정할 수 있습니다.

MongoDB에서 느린 작업 기록

클라이언트 작업(예: 쿼리)은 느린 작업 임계값보다 오래 걸리거나 로그 상세 수준이 1 이상으로 설정된 경우 기록됩니다.

읽기/쓰기 작업의 경우 MongoDB 4.2부터 프로파일러 항목 및 진단 로그 메시지(예:mongod/mongos 로그 메시지)에는 다음이 포함됩니다.

  1. queryHash, 동일한 쿼리 형식으로 느린 검색을 감지할 수 있는 기능;
  2. planCacheKey는 느린 쿼리에 대한 쿼리 계획 캐시에 대한 추가 정보를 제공합니다.

이제 느린 작업 로그 메시지에 MongoDB 5.0부터 클라이언트 IP 주소를 지정하는 remote 열이 포함됩니다.

주어진 예제 출력에는 느린 집계 작업에 대한 정보가 포함됩니다.

{"t":{"$date":"2020-05-20T20:10:08.731+00:00"},"s":"I",  "c":"COMMAND",  "id":51803,   "ctx":"conn281","msg":"Slow query","attr":{"type":"command","ns":"stocks.trades","appName":"MongoDB Shell","command":{"aggregate":"trades","pipeline":[{"$project":{"ticker":1.0,"price":2.0,"priceGTE110":{"$gte":["$price",111.0]},"_id":0.0}},{"$sort":{"price":-1.0}}],"allowDiskUse":true,"cursor":{},"lsid":{"id":{"$uuid":"fa658f9e-9cd6-42d4-b1c8-c9160fabf2a2"}},"$clusterTime":{"clusterTime":{"$timestamp":{"t":1590005405,"i":1}},"signature":{"hash":{"$binary":{"base64":"AAAAAAAAAAAAAAAAAAAAAAAAAAA=","subType":"0"}},"keyId":0}},"$db":"test"},"planSummary":"COLLSCAN","cursorid":1912190691485054730,"keysExamined":0,"docsExamined":1000001,"hasSortStage":true,"usedDisk":true,"numYields":1002,"nreturned":101,"reslen":17738,"locks":{"ReplicationStateTransition":{"acquireCount":{"w":1119}},"Global":{"acquireCount":{"r":1119}},"Database":{"acquireCount":{"r":1119}},"Collection":{"acquireCount":{"r":1119}},"Mutex":{"acquireCount":{"r":117}}},"storage":{"data":{"bytesRead":232899899,"timeReadingMicros":186017},"timeWaitingMicros":{"cache":849}},"remote": "192.168.14.15:37666","protocol":"op_msg","durationMillis":22427}}

remoteOpWaitMillis 필드에서 샤드 대기 시간 가져오기

MongoDB 5.0부터 remoteOpWaitMillis 로그 필드를 사용하여 샤드 결과에 대한 대기 시간(밀리초)을 얻을 수 있습니다.

remoteOpWaitMillis에 대해 다음 값만 보고됩니다.

  1. 작업이 느리면 로깅이 활성화됩니다.
  2. 결과를 결합하는 샤드 또는 몽고

로그에서 durationMillisremoteOpWaitMillis 시간 열을 비교하여 병합 작업 또는 샤드 문제로 인해 느린 쿼리가 발생하는지 확인하십시오. durationMillis는 쿼리를 완료하는 데 걸린 전체 시간입니다.

구체적으로,

  1. durationMillisremoteOpWaitMillis를 초과하면 샤드 응답을 기다리는 데 대부분의 시간이 소요됩니다. 예를 들어 18durationMillis15remoteOpWaitMillis는 허용되는 값입니다.
  2. durationMillisremoteOpWaitMillis보다 상당히 크면 병합을 수행하는 데 대부분의 시간이 소비된 것입니다. 예를 들어 durationMillis150이고 remoteOpWaitMillis15입니다.

mongosh 내의 로그 쿼리 결과 필터링

getLog의 출력은 결과를 더 쉽게 읽거나 특정 기준과 일치하도록 필터링할 수 있습니다.

다음 명령은 각 로그 메시지에서 문자 이스케이프를 제거하면서 log 필드(모든 현재 로그 이벤트의 배열 포함)만 인쇄합니다.

db.adminCommand( { getLog:'global'} ).log.forEach(x => {print(x)})

이 작업에서 getLog의 출력은 MongoDB log file.과 동일한 형식으로 표시됩니다.

주의: getLog는 마지막으로 기록된 1024개의 mongod 이벤트만 표시하며 MongoDB 로그 파일을 대체하기 위한 것이 아닙니다.

jq를 사용하여 mongosh 외부의 로그 쿼리 결과 필터링

타사 jq 명령줄 프로그램은 MongoDB 구조적 로깅을 처리할 때 편리합니다. 로그 항목의 빠른 예쁜 인쇄와 강력한 키 기반 일치 및 필터링이 가능합니다.

jq는 Linux, Windows 및 macOS용 무료 오픈 소스 JSON 파서입니다.

getLog 출력과 함께 jq를 활용하려면 mongosh-eval 옵션을 사용해야 합니다. 다음 작업은 복제와 관련된 로그 메시지만 표시되도록 jq를 사용하여 REPL 구성 요소를 필터링합니다.

mongosh --quiet --eval "db.adminCommand( { getLog:'global'} ).log.forEach(x => {print(x)})" | jq -c '. | select(.c=="REPL")'

mongosh에 필요한 연결 관련 인수(예: -host 또는 -port.)를 제공하도록 주의하십시오.

mongosh --quiet --eval "db.adminCommand( { getLog:'global'} ).log.forEach(x => {print(x)})" | jq -r ".msg" | sort | uniq -c | sort -rn | head -10

사용 가능한 로그 필터 검색

mongosh에서 실행되는 다음 작업은 getLog로 전달하기 위해 사용 가능한 로그 필터를 반환합니다.

db.adminCommand( { getLog: "" } )

이 작업은 다음 문서를 반환합니다.

{ "names" : [ "global", "startupWarnings" ], "ok" : 1 }

로그에서 최근 이벤트 검색

mongosh에서 실행되는 다음 명령은 mongod의 가장 최근 글로벌 이벤트를 가져옵니다.

db.adminCommand( { getLog : "global" } )

이 작업은 다음과 같은 문서를 생성합니다.

MongoDB 로그 쿼리 - 결과 1

관련 문장 - MongoDB Query