🌿Logstash를 사용하여 CSV 파일 정보 추출 및 Kibana 시각화
insa.csv, insa.conf
사번,성명,주민등록번호,주소,소속,직위,입사일
KR-001,유진하,620203-1005733,서울특별시 은평구 갈현동 435,홍보부,대리,1996-09-27
KR-002,황의찬,560903-2009775,경기도 고양시 일산구 일산동 526,영업부,대리,2002-04-30
KR-003,배한성,730325-1002605,서울특별시 은평구 수색동 631,홍보부,차장,1994-03-20
KR-004,김경민,620702-1003034,서울특별시 중랑구 상봉동 87,기획실,대리,1994-11-29
KR-005,배태욱,590226-1005856,서울특별시 은평구 진관내동 95,기획실,부장,2001-08-30
KR-006,김순정,660208-2006000,서울특별시 은평구 신사동 200,기획실,대리,2000-06-10
KR-007,강태평,690209-1004056,경기도 성남시 분당구 분당동 34,전산실,차장,2003-05-28
KR-008,배철수,560531-1004812,서울특별시 도봉구 방학동 777,총무부,부장,2001-02-20
KR-009,은지원,560411-1002318,서울특별시 서초구 서초동 103,총무부,부장,1991-09-15
KR-010,양희은,680806-2003951,서울특별시 은평구 불광동 220,기획실,과장,1994-02-06
KR-011,은예영,580715-2004349,경기도 고양시 일산구 일산동 847,홍보부,사원,2000-04-17
KR-012,이솔희,681028-2004638,서울특별시 성북구 길음동 164,전산실,차장,1996-04-08
KR-013,서만복,611015-1006025,서울특별시 도봉구 창동 742,총무부,차장,2002-04-13
KR-014,이철희,740308-1006396,서울특별시 은평구 불광동 220,기획실,과장,1990-01-10
KR-015,박은영,720707-2008872,서울특별시 강서구 방화동 55,전산실,부장,1990-02-19
KR-016,엄희숙,620223-2008900,서울특별시 중랑구 상봉동 426,영업부,사원,1993-09-21
KR-017,전성옥,540105-2007385,서울특별시 은평구 진관외동 492,총무부,부장,1996-08-25
KR-018,김석구,540721-1006695,서울특별시 은평구 구산동 443,영업부,대리,1992-06-27
KR-019,안태희,540510-2005007,서울특별시 서초구 서초동 115,홍보부,차장,1999-03-20
KR-020,송도순,731128-2006358,경기도 고양시 일산구 일산동 12,전산실,사원,2003-05-04
KR-021,김형식,560726-1008604,서울특별시 은평구 응암동 434,기획실,과장,1990-03-14
KR-022,오태호,640816-1007304,서울특별시 강서구 방화동 212,영업부,대리,1996-06-05
KR-023,최은지,590211-2002611,서울특별시 은평구 신사동 211,기획실,사원,1994-11-03
KR-024,채연희,620111-2005622,서울특별시 은평구 갈현동 95,기획실,사원,1998-02-03
KR-025,황석영,640904-1003139,경기도 성남시 분당구 분당동 3474,기획실,대리,1993-11-26
input {
file {
path => "/home/ubuntu/insa.csv"
start_position => "beginning"
sincedb_path => "/dev/null"
}
}
filter {
csv {
columns => ["seq", "name", "jumin", "address", "buseo", "position", "hiredate"]
separator => ","
}
}
output {
elasticsearch {
hosts => ["localhost:9200"]
index => "insa"
document_id => "%{seq}"
}
}
insa.csv, insa.conf 파일을 이용하여 데이터를 elasticsearch로 옮기고, Kibana로 시각화해보도록 하자.
filter가 들어 있기 때문에 Logstash가 데이터를 separator(",") 단위로 쪼개서 각각 columns의 값으로 넣게 된다.
파일을 저장할 폴더 열기
$ cd ~
$ explorer.exe .
데이터 있는 줄만 남겨 놓아야 하므로 제일 위에 있는 헤더와 아래에 비어 있는 라인은 지우도록 한다.
포맷이 일정하지 않으면 옮길 때 에러가 날 수 있다.
Elasticsearch로 데이터 이동
$ sudo /usr/share/logstash/bin/logstash -f insa.conf
위 코드를 실행하면 conf 파일이 csv 파일을 읽어서 elasticsearch로 복사하게 된다.
wsl --shutdown
이미 Logstash가 동작중이어서 에러가 발생한다면 WSL을 껐다 켜 주면 된다.
Dev Tools에서 데이터 확인
GET insa
GET insa/_search
DELETE insa
host에는 현재 컴퓨터의 이름이 들어가는데, 이는 필요 없는 데이터이다.
데이터를 집어 넣은 시각인 timestamp, version 등등 역시 필요 없으므로 인덱스를 삭제하고 다시 데이터를 넣도록 한다.
insa.conf 파일 수정
$ sudo /usr/share/logstash/bin/logstash -f insa.conf
input {
file {
path => "/home/ubuntu/insa.csv"
start_position => "beginning"
sincedb_path => "/dev/null"
}
}
filter {
csv {
columns => ["seq", "name", "jumin", "address", "buseo", "position", "hiredate"]
separator => ","
}
mutate {
remove_field => ["@version", "@timestamp", "message", "path", "host"]
}
}
output {
elasticsearch {
hosts => ["localhost:9200"]
index => "insa"
document_id => "%{seq}"
}
}
conf 파일을 수정하고 다시 데이터를 넣는다.
GET insa/_mapping
DELETE insa
PUT insa
{
"mappings" : {
"properties" : {
"address" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"buseo" : {
"type" : "keyword"
},
"hiredate" : {
"type" : "date"
},
"jumin" : {
"type" : "keyword"
},
"name" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"position" : {
"type" : "keyword"
},
"seq" : {
"type" : "keyword"
}
}
}
}
mapping 정보를 확인하고 다시 insa를 삭제한다.
전체 검색을 하는 경우 text를 keyword로 내부 타입을 일부 변환하였다.
$ sudo /usr/share/logstash/bin/logstash -f insa.conf
이제 다시 Logstash로 데이터를 옮겨 담는다.
Dashboard 생성
인덱스 패턴 생성
http://localhost:5601/app/management/kibana/indexPatterns
Create index pattern 버튼을 누른다.
내용을 채운 뒤에 Dreate index pattern 버튼을 클릭한다.
날짜 데이터가 있는 경우에 Timestamp field를 선택한다.
Visualize Libarary 생성
Aggregation은 Term을 선택하고, Field는 buseo를 선택한다.
기본적으로 날짜 필터가 걸려 있으므로 날짜를 최근 30년까지 지정해 주도록 한다.
Dashboard 추가
오른쪽 상단의 Save를 클릭하고 Add to dashboard에서 New로 저장한다.
이곳에서 Dashboard를 편집할 수 있다.
Buckets 추가
버킷을 추가하는 경우 1차, 2차로 데이터를 추가할 수 있다.
또한 요소를 클릭하면 필터를 추가하여 확인할 수 있다.
Dashboard 구성
<iframe src="http://localhost:5601/app/dashboards#/view/077aa730-9e13-11ee-a361-a15e50aca289?embed=true&_g=(filters:!(),refreshInterval:(pause:!f,value:10000),time:(from:now-30y,to:now))&_a=(description:'',filters:!(),fullScreenMode:!f,options:(hidePanelTitles:!f,syncColors:!f,useMargins:!t),panels:!((embeddableConfig:(enhancements:(),savedVis:(data:(aggs:!((enabled:!t,id:'1',params:(),schema:metric,type:count),(enabled:!t,id:'2',params:(field:buseo,missingBucket:!f,missingBucketLabel:Missing,order:desc,orderBy:'1',otherBucket:!f,otherBucketLabel:Other,size:5),schema:segment,type:terms)),searchSource:(filter:!(),index:'993ef750-9e10-11ee-8380-abe1e0079a51',query:(language:kuery,query:''))),description:'',id:'',params:(addLegend:!t,addTimeMarker:!f,addTooltip:!t,categoryAxes:!((id:CategoryAxis-1,labels:(filter:!t,show:!t,truncate:100),position:bottom,scale:(type:linear),show:!t,style:(),title:(),type:category)),detailedTooltip:!t,grid:(categoryLines:!f),labels:(show:!f),legendPosition:right,maxLegendLines:1,palette:(name:default,type:palette),radiusRatio:0,row:!t,seriesParams:!((circlesRadius:1,data:(id:'1',label:Count),drawLinesBetweenPoints:!t,interpolate:linear,lineWidth:2,mode:stacked,show:!t,showCircles:!t,type:histogram,valueAxis:ValueAxis-1)),thresholdLine:(color:%23E7664C,show:!f,style:full,value:10,width:1),times:!(),truncateLegend:!t,type:histogram,valueAxes:!((id:ValueAxis-1,labels:(filter:!f,rotate:0,show:!t,truncate:100),name:LeftAxis-1,position:left,scale:(mode:normal,type:linear),show:!t,style:(),title:(text:''),type:value))),title:'%EB%B6%80%EC%84%9C%EB%B3%84%20%EC%9D%B8%EC%9B%90%EC%88%98',type:histogram,uiState:())),gridData:(h:17,i:'06673350-02cb-4797-a668-d95ebf8f622a',w:21,x:0,y:0),panelIndex:'06673350-02cb-4797-a668-d95ebf8f622a',type:visualization,version:'7.17.15'),(embeddableConfig:(enhancements:(),savedVis:(data:(aggs:!((enabled:!t,id:'1',params:(),schema:metric,type:count),(enabled:!t,id:'2',params:(field:buseo,missingBucket:!f,missingBucketLabel:Missing,order:desc,orderBy:'1',otherBucket:!f,otherBucketLabel:Other,size:5),schema:segment,type:terms),(enabled:!t,id:'3',params:(field:position,missingBucket:!f,missingBucketLabel:Missing,order:desc,orderBy:'1',otherBucket:!f,otherBucketLabel:Other,size:5),schema:segment,type:terms)),searchSource:(filter:!(),index:'993ef750-9e10-11ee-8380-abe1e0079a51',query:(language:kuery,query:''))),description:'',id:'',params:(addLegend:!f,addTooltip:!t,distinctColors:!f,isDonut:!t,labels:(last_level:!f,percentDecimals:2,position:default,show:!t,truncate:100,values:!t,valuesFormat:percent),legendPosition:right,maxLegendLines:1,nestedLegend:!f,palette:(name:default,type:palette),truncateLegend:!t,type:pie),title:'%EB%B6%80%EC%84%9C%EB%B3%84%20%EC%A7%81%EA%B8%89',type:pie,uiState:()),vis:(legendOpen:!f)),gridData:(h:17,i:a652977e-74f5-4716-bbae-4c9b8432400e,w:15,x:21,y:0),panelIndex:a652977e-74f5-4716-bbae-4c9b8432400e,type:visualization,version:'7.17.15'),(embeddableConfig:(enhancements:(),savedVis:(data:(aggs:!((enabled:!t,id:'1',params:(),schema:metric,type:count),(enabled:!t,id:'2',params:(field:buseo,missingBucket:!f,missingBucketLabel:Missing,order:desc,orderBy:'1',otherBucket:!f,otherBucketLabel:Other,size:5),schema:bucket,type:terms)),searchSource:(filter:!(),index:'993ef750-9e10-11ee-8380-abe1e0079a51',query:(language:kuery,query:''))),description:'',id:'',params:(autoFitRowToContent:!f,perPage:10,percentageCol:'',showMetricsAtAllLevels:!f,showPartialRows:!f,showToolbar:!f,showTotal:!f,totalFunc:sum),title:'%EB%B6%80%EC%84%9C%EB%B3%84%EC%9D%B8%EC%9B%90%EC%88%98(%ED%91%9C)',type:table,uiState:())),gridData:(h:17,i:'1ef0b5fd-fc20-4ea5-a142-f539cb35c585',w:12,x:36,y:0),panelIndex:'1ef0b5fd-fc20-4ea5-a142-f539cb35c585',type:visualization,version:'7.17.15')),query:(language:kuery,query:''),tags:!(),timeRestore:!f,title:%EC%9D%B8%EC%82%AC,viewMode:edit)" height="600" width="800"></iframe>
차트를 구성하고, 적당하게 위치를 결정하면 된다.
Share > Embed Code에서 iFrame code를 복사하고, 이를 JSP 파일에 붙여 넣기 하면 된다.
현재 전 세계의 80% 이상이 Kibana로 로그 분석을 한다. 이를 이용해서 로그 분석을 하거나 검색 등의 결과를 확인할 수 있다.
프로젝트에 iframe 삽입
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="https://me2.do/5BvBFJ57">
<style>
iframe {
width: 1190px;
margin: 0 auto;
border: 0;
}
</style>
</head>
<body class="wide">
<!-- kibana.jsp -->
<h1>Elasticsearch <small>DashBoard</small></h1>
<iframe src="http://localhost:5601/app/dashboards#/view/077aa730-9e13-11ee-a361-a15e50aca289?embed=true&_g=(filters:!(),refreshInterval:(pause:!f,value:10000),time:(from:now-30y,to:now))&_a=(description:'',filters:!(),fullScreenMode:!f,options:(hidePanelTitles:!f,syncColors:!f,useMargins:!t),panels:!((embeddableConfig:(enhancements:(),savedVis:(data:(aggs:!((enabled:!t,id:'1',params:(),schema:metric,type:count),(enabled:!t,id:'2',params:(field:buseo,missingBucket:!f,missingBucketLabel:Missing,order:desc,orderBy:'1',otherBucket:!f,otherBucketLabel:Other,size:5),schema:segment,type:terms)),searchSource:(filter:!(),index:'993ef750-9e10-11ee-8380-abe1e0079a51',query:(language:kuery,query:''))),description:'',id:'',params:(addLegend:!t,addTimeMarker:!f,addTooltip:!t,categoryAxes:!((id:CategoryAxis-1,labels:(filter:!t,show:!t,truncate:100),position:bottom,scale:(type:linear),show:!t,style:(),title:(),type:category)),detailedTooltip:!t,grid:(categoryLines:!f),labels:(show:!f),legendPosition:right,maxLegendLines:1,palette:(name:default,type:palette),radiusRatio:0,row:!t,seriesParams:!((circlesRadius:1,data:(id:'1',label:Count),drawLinesBetweenPoints:!t,interpolate:linear,lineWidth:2,mode:stacked,show:!t,showCircles:!t,type:histogram,valueAxis:ValueAxis-1)),thresholdLine:(color:%23E7664C,show:!f,style:full,value:10,width:1),times:!(),truncateLegend:!t,type:histogram,valueAxes:!((id:ValueAxis-1,labels:(filter:!f,rotate:0,show:!t,truncate:100),name:LeftAxis-1,position:left,scale:(mode:normal,type:linear),show:!t,style:(),title:(text:''),type:value))),title:'%EB%B6%80%EC%84%9C%EB%B3%84%20%EC%9D%B8%EC%9B%90%EC%88%98',type:histogram,uiState:())),gridData:(h:17,i:'06673350-02cb-4797-a668-d95ebf8f622a',w:21,x:0,y:0),panelIndex:'06673350-02cb-4797-a668-d95ebf8f622a',type:visualization,version:'7.17.15'),(embeddableConfig:(enhancements:(),savedVis:(data:(aggs:!((enabled:!t,id:'1',params:(),schema:metric,type:count),(enabled:!t,id:'2',params:(field:buseo,missingBucket:!f,missingBucketLabel:Missing,order:desc,orderBy:'1',otherBucket:!f,otherBucketLabel:Other,size:5),schema:segment,type:terms),(enabled:!t,id:'3',params:(field:position,missingBucket:!f,missingBucketLabel:Missing,order:desc,orderBy:'1',otherBucket:!f,otherBucketLabel:Other,size:5),schema:segment,type:terms)),searchSource:(filter:!(),index:'993ef750-9e10-11ee-8380-abe1e0079a51',query:(language:kuery,query:''))),description:'',id:'',params:(addLegend:!f,addTooltip:!t,distinctColors:!f,isDonut:!t,labels:(last_level:!f,percentDecimals:2,position:default,show:!t,truncate:100,values:!t,valuesFormat:percent),legendPosition:right,maxLegendLines:1,nestedLegend:!f,palette:(name:default,type:palette),truncateLegend:!t,type:pie),title:'%EB%B6%80%EC%84%9C%EB%B3%84%20%EC%A7%81%EA%B8%89',type:pie,uiState:()),vis:(legendOpen:!f)),gridData:(h:17,i:a652977e-74f5-4716-bbae-4c9b8432400e,w:15,x:21,y:0),panelIndex:a652977e-74f5-4716-bbae-4c9b8432400e,type:visualization,version:'7.17.15'),(embeddableConfig:(enhancements:(),savedVis:(data:(aggs:!((enabled:!t,id:'1',params:(),schema:metric,type:count),(enabled:!t,id:'2',params:(field:buseo,missingBucket:!f,missingBucketLabel:Missing,order:desc,orderBy:'1',otherBucket:!f,otherBucketLabel:Other,size:5),schema:bucket,type:terms)),searchSource:(filter:!(),index:'993ef750-9e10-11ee-8380-abe1e0079a51',query:(language:kuery,query:''))),description:'',id:'',params:(autoFitRowToContent:!f,perPage:10,percentageCol:'',showMetricsAtAllLevels:!f,showPartialRows:!f,showToolbar:!f,showTotal:!f,totalFunc:sum),title:'%EB%B6%80%EC%84%9C%EB%B3%84%EC%9D%B8%EC%9B%90%EC%88%98(%ED%91%9C)',type:table,uiState:())),gridData:(h:17,i:'1ef0b5fd-fc20-4ea5-a142-f539cb35c585',w:12,x:36,y:0),panelIndex:'1ef0b5fd-fc20-4ea5-a142-f539cb35c585',type:visualization,version:'7.17.15')),query:(language:kuery,query:''),tags:!(),timeRestore:!f,title:%EC%9D%B8%EC%82%AC,viewMode:edit)" height="600" width="800"></iframe>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script>
</script>
</body>
</html>
webapp 폴더에 kibana.jsp 파일을 만들고 안에 코드를 넣은 뒤에 실행한다.
iframe은 별도의 페이지를 삽입하는 클라이언트 기술이다.