Elasticsearch-dsl, Django 삽질 복기(2)
- 공유 링크 만들기
- X
- 이메일
- 기타 앱
Elasticsearch-dsl, Django 삽질 복기(2)
분석하려는 로그 메시지에 포함된 json 형식의 데이터를 사용하려는 과정에서 두 가지 문제에 부딪혔다.
1. Search API 에서 json 키값을 field로 이용하는 방법.
2. template 단에서 json 키값별로 핸들링하는 방법.
로그 포맷에 대한 표준이 없다보니 로그 데이터의 패턴이 다양한데 그 중 간단한 형태 하나를 예로 보자.
2020-02-03 13:39:14 [INFO ] [OPERATION] - {"logType":"[REMOVE JOB]","mchnId":"T985","mchnTp":"YT","type":"DELETE","jobKey":"MEDU7911824120200203121004"}
이전 글에 적은 적 있지만 Logstash 설정에서 grok 을 이용해서 json 형식의 데이터가 포함되어 있을 경우에는 이를 따로 분리했고 이걸 아래 같은 식으로 ES 매핑 처리했었다.
"mappings" : { "dynamic": false, "properties" : { "@timestamp" : { "type" : "date" }, ... "loglevel" : { "type" : "keyword" }, "message" : { "type" : "text", "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 256 } } }, "jsonmsg" : { "properties" : { "mchnId" : { "type" : "keyword" }, "msgType" : { "type" : "keyword" }, ... "msgJson" : { "properties" : { "connected" : { "type" : "boolean" }, ... }
이 설정 상태에서 double underbar 형식을 사용해서 테스트해봤을 때는 별 다른 이상 없었다.
q = Q("match", jsonmsg__msgJson__mchnId='T768')
그런데, 실 개발들어가서 구현하다보니 이것저것 꼬이기 시작했다. double underbar 를 사용하는 것도 제약이 꽤 있었고 그 외에도 다양한 에러에 부딪혔다. 해결 시도 과정에서 다양한 문제들 접했는데 따로 기록해두지 않아 발생 문제들 세세히 정리는 못하겠고 결론으로 곧장 넘어가면 "nested" 를 사용하는 방식으로 해결.
문서들 찾아 읽다보니 Document 매핑 타입 중 nested 오브젝트 처리를 위해 "nested"란 타입이 제공되고 있음을 알았다.
"nested" 사용하기 위해 매핑 설정을 아래와 같이 약간 바꾸었다.
"mappings" : { ... "jsonmsg" : { "type": "nested", "properties" : { "mchnId" : { "type" : "keyword" }, "msgType" : { "type" : "keyword" }, ... "msgJson" : { "type": "nested", "properties" : { "connected" : { "type" : "boolean" }, ...
이 설정 이용해서 데이터 다시 인덱싱한 후에 "nested" 와 kwargs 이용해서 해결(이 단계에서 model 의 jsonmsg 를 TextField 에서 JSONField 로 수정했는지 다음 단계에서 했는지는 가물가물)
def test_nested(phrase): q = Q('bool', must=[ Q("nested", path="jsonmsg", query=Q("match", **{'jsonmsg.mchnId': phrase})), ], ) s = Search(using=client, index="eep-log") for item in s: print(item.jsonmsg, item["@timestamp"], item.jsonmsg.jobKey)
jsonmsg 값 결과가 좀 애매하긴 했지만 "nested"로 1번 문제 해결되었다 싶어서 실 애플리케이션에 이 방식 적용 테스트하는데 2번 문제 봉착.
현상은 이랬다.
{'logType': '[REMOVE JOB]', 'type': 'DELETE', 'mchnTp': 'YT'...}
위에 결과처럼 json 값이 60자 까지만 표시되고 나머지는 '...' 로 생략되어 표시된다. 게다가 'jsonmsg.키' 값은 텅 비어있다.
test_nested 에서는 '...' 로 생략 표시되는건 동일했지만 'jsonmsg.키'는 출력되었는데 무엇이 다른가?
search 처리 후 그 결과를 웹 화면까지 전달하는 과정 중 어디에서 문제인걸까?
에러는 안나니 기초 없이 덤벼든 내 입장에서는 더 막막했고 그래서 의심 가는 부분 몇 곳을 일부러 찔러 에러를 발생시켜 보다보니 그제야 차이점이 눈에 들어왔다.
백단의 search 처리 후 프론트와 http 통신하기 위해 serialize 하는 과정에서 뭔가 문제가 있다!
감은 잡았지만 기초 없다니 숱한 헛발질 후에 내린 추정은 jsonmsg 값을 TextField 로 선언해서 처리한게 모든 문제의 원인일거라는 거였다.
이 후의 초보의 삽질은 너무 장황하여 스킵하고 결론으로 직행.
jsonmsg 를 JSONField 로 선언하고 그 값을 to_dict 처리.
models.py : jsonmsg = JSONField 로 필드 타입 변경
class EepLog(models.Model): timestamp = models.DateTimeField() message = TextField() jsonmsg = JSONField(blank=True, null=True, default="")
serializers.py : to_representation 구현하고 dictionary 타입으로 리턴값 변경.
class JSONSerializerField(serializers.Field): def to_internal_value(self, data): return data def to_representation(self, value): return value.to_dict() class EeLogSerializer(serializers.ModelSerializer): jsonmsg = JSONSerializerField() class Meta: model = EepLog # filelds = '__all__' fields = ( 'message', 'jsonmsg', 'timestamp', )
이렇게 변경하니 생략 표시되던거랑 'jsonmsg.키'값 비어 있던 문제 다 해결됨.
여기까지가 현재까지의 진행 상황.
아직 해결하지 못한 중요 과제는 json 메시지 내에 값으로 또다른 json 메시지가 포함되어 있는 경우(이런 nested json 이 여러 단계로 구성되어 있는 경우도 있고)는 핸들링하는 방법 못 찾은거. 가령 'jsonmsg.msgJson.truck.mchnId' 같은 방식은 동작하지 않고 있다. 여러 단계의 nested json 을 각각 dictionary 로 변환해야 하는건가 싶긴한데 아직은 어디서 출발해야 할지 엄두가 안난다.
from http://tzara.tistory.com/107 by ccl(A) rewrite - 2020-03-25 11:54:11
- 공유 링크 만들기
- X
- 이메일
- 기타 앱
댓글
댓글 쓰기