Elasticsearch와 Logstash, Kibana 를 사용할때 아무래도 기본 Defualt 설정보다 Security를 이용해서


계정, 비밀번호를 셋팅해서 사용하면 더 안전하지 않을까 하고 알아보던 중 해당 기능은 X-pack으로 설정을 해야되는데


6.3 이후로 X-pack과 통합되면서 라이센스 부분이 걸려서 Security를 사용하지 못하하네요.


골드부터 Security를 사용 가능하다고 나오니.. 모니터링 시스템도 일부 지원하지만 제대로 사용하라면 라이센스가 필요하군요.


우선은 기본으로만 설정해서 외부접근이 안되게 사용해야 될거같습니다.


출처: https://www.elastic.co/subscriptions

아무런 설정을 하지않고 Kibana에 접속을 한뒤 왼쪽 메뉴에 Monitoring 메뉴에 들어가면


모니터링 설정이 OFF 되어있다고 메세지가 나오면서 가운데에 Turn On Data 라는 버튼이 보일 것입니다.


이 버튼을 클릭하고 수 초를 기다리고 나면 하단과 같이 Elasticsearch과 Kibana를 모니터링 하는 화면이 보입니다.


그외에 Beats와 Logstash 도 Monitoring이 가능합니다.



스프링 로그를 효율적으로 관리(?) 통계를 내기 위해 Spring Boot 와 ELK(Elasticsearch, Logstash, Kibana)를 통해서 


로그를 수집하기로 했습니다.


로그 수집하는 플로우는


Spring Boot ---> Logstash ---> Elasticsearch ---> Kibana를 통해 통계 확인 입니다.



우선은 Spring Boot는 기존에 있는 프로젝트 그대로 사용하기로 하고 ELK 를 먼저 셋팅해 보겠습니다.


먼저 ELK를 아래의 사이트에서 각 OS와 bit 에 맞게 다운로드를 해서 설치를 합니다.

(저는 윈도우10에서 진행하였습니다.)


Elasticsearch 다운로드: https://www.elastic.co/kr/downloads/elasticsearch

Kibans 다운로드: https://www.elastic.co/kr/downloads/kibana

Logstash 다운로드: https://www.elastic.co/kr/downloads/logstash



다운로드를 하고 설치까지 마쳤으면 Logstash 설정을 먼저 진행합니다.


Logstash 설정파일은 설치한 위치에서 Config 폴더 안에 보면 logstash-sample.conf 파일이 있습니다.


이 파일을 하나 복사해서 logstash.conf 라고 파일을 하나 생성합니다.


생성이 완료 되면 logstash.conf 파일을 열어서 설정파일을 수정합니다.



input 설정은 Spring Boot 와 Logstash 와 통신하기위해 TCP를 사용하였고 포트는 4560을 사용합니다.


그리고 코덱은 json을 라인별로 읽을 수 있게 설정하였습니다.


output은 Logstash에서 받은 로그를 Elasticsearch로 전송하기 위한 설정입니다.


설치한 Elasticsearch의 host 기본정보는 localhost:9200 이고 Index는 Elasticsearch에서 검색할 수 있게 패턴을 


설정할 수 있습니다. Index를 logstash-오늘날짜로 변경하였습니다.



그리고 Spring Boot logback 을 설정합니다.


기존에 작성되어있는 Spring Boot logback 설정에서 아래의 부분을 추가합니다.



<!-- Log Stash 사용시 사용할 TCP 통신 정보 -->
<appender name="stash" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
<destination>127.0.0.1:4560</destination>
<encoder class="net.logstash.logback.encoder.LogstashEncoder"></encoder>
</appender>


<root level="INFO">
<appender-ref ref="dailyRollingFileAppender" />
<appender-ref ref="stash" />
</root>


이 두 부분을 추가합니다.


로그가 쌓일때 Logstash 에서 설정한 TCP Port 4560에 동일한 서버에 있으니 127.0.0.1 로 설정하였습니다.


그리고 실제로 로그가 동작하기 위해 root 태그 아래 부분에 설정하였습니다.


이렇게 설정을 완료 한 후 Logstash를 실행하고 Spring Boot를 실행하면 됩니다.


Logstash 실행방법은 CMD 에서 Logstash 설치한 폴더에 bin폴더로 이동후 logstash -f ../config/logstash.conf 를 입력하면 실행이 됩니다.



그리고 Elasticsearch 실행방법 입니다.


Elasticsearch 실행 방법은 Elasticsearch 설치한 폴더에서 bin 폴더로 이동 후 CMD 에서 elasticsearch 를 입력하면 실행이 됩니다.


만약 포트 정보나 그외의 Elasticsearch 정보를 변경하고 싶으면 Elasticsearch 설치 폴더에서 config 폴더로 이동 후  elasticsearch.yml 파일에서 수정하시면


됩니다. 


실행이 정상적으로 됐는지 확인하려면 브라우저에서 http://localhost:9200/ 를 입력하면 아래와 같은 화면이 나오면 정상적으로 실행이 된것입니다.





마지막으로 Kibans 실행방법입니다.


Kibana도 Elasticsearchd와 마찬가지로 Kibana 설치한 폴더에서 bin 폴더로 이동 후 CMD 에서 kibana 를 입력하면 실행이 됩니다.


Kibana또한 실행이 되었는지 확인을 하려면 브라우저에서 http://localhost:5601 를 입력하면 아래와 같은 화면이 나오면 정상적으로 실행이 된것입니다.







첫번째로 할일은 build.gradle에 logback encoder를 추가 해줍니다.


compile group: 'net.logstash.logback', name: 'logstash-logback-encoder', version: '5.2' // Log를 JSON 형식으로 표현하기 위해 사용


그다음에는 로그 포멧을 위해 Java Class 파일 2개를 생성합니다.


패키지 위치는 해당 프로젝트 아래에만 있으면 됩니다. 저는 이렇게 두개를 만들었습니다.


package kr.co.eda.kbn.logback;

import com.fasterxml.jackson.databind.MappingJsonFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.util.StdDateFormat;
import net.logstash.logback.decorate.JsonFactoryDecorator;

/**
* ISO08601 데코레이터
*
* @since 2018-12-19
* @see {@link JsonFactoryDecorator}
*/
public class ISO8601DateDecorator implements JsonFactoryDecorator {

@Override
public MappingJsonFactory decorate(MappingJsonFactory factory) {

ObjectMapper codec = factory.getCodec();
codec.setDateFormat(new StdDateFormat());

return factory;
}
}

원래는 ISO08601DateFormat를 썻지만 현재 사용하는 logback encoder에서 Deprecated가 되어서 StdDateFormat를 사용하였습니다.


package kr.co.eda.kbn.logback;

import com.fasterxml.jackson.core.JsonGenerator;
import net.logstash.logback.decorate.JsonGeneratorDecorator;

/**
* 로그를 JSON으로 출력하기 위한 데코레이터
*
* @since 2018-12-19
* @see {@link JsonGeneratorDecorator}
*/
public class PrettyPrintingDecorator implements JsonGeneratorDecorator {

@Override
public JsonGenerator decorate(JsonGenerator generator) {

return generator.useDefaultPrettyPrinter();
}
}


마지막으로 실제 Spring 에서 로그를 설정하는 부분으로 가서 encoder를 지정해줍니다.


<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="30 seconds">

<!-- Spring Boot의 logback 설정은 유지하면서 확장 -->
<include resource="org/springframework/boot/logging/logback/base.xml"/>

<!-- 로그 저장 할 위치 -->
<property name="LOG_DIR" value="D:/p_project/logs/" />

<appender name="dailyRollingFileAppender"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<prudent>true</prudent>
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<jsonGeneratorDecorator class="kr.co.eda.kbn.logback.PrettyPrintingDecorator"/>
<jsonFactoryDecorator class="kr.co.eda.kbn.logback.ISO8601DateDecorator"/>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_DIR}kbn.%d{yyyy-MM-dd}.json</fileNamePattern>
<maxHistory>30</maxHistory> <!-- 30일 전 까지의 로그만 저장 -->
</rollingPolicy>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
</appender>

<logger name="org.springframework.web" level="INFO"/>
<logger name="org.thymeleaf" level="INFO"/>-
<logger name="org.hibernate.SQL" level="INFO"/>
<logger name="org.quartz.core" level="INFO"/>
<logger name="org.h2.server.web" level="INFO"/>

<logger name="jdbc" level="OFF" />
<logger name="jdbc.sqlonly" level="OFF"/>
<logger name="jdbc.sqltiming" level="DEBUG"/>
<logger name="jdbc.audit" level="OFF"/>
<logger name="jdbc.resultset" level="OFF"/>
<logger name="jdbc.resultsettable" level="DEBUG"/>
<logger name="jdbc.connection" level="OFF"/>

<root level="INFO">
<appender-ref ref="dailyRollingFileAppender" />
</root>
</configuration>

여기 파일에서 추가 된 부분은


<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<jsonGeneratorDecorator class="kr.co.eda.kbn.logback.PrettyPrintingDecorator"/>
<jsonFactoryDecorator class="kr.co.eda.kbn.logback.ISO8601DateDecorator"/>
</encoder>


이 부분 입니다.


이렇게 설정을 끝나고 로그를 찍고 난뒤 로그 파일을 열어보면




이렇게 로그가 JSON 형식으로 찍히는것을 볼 수 있습니다.

'Spring' 카테고리의 다른 글

[SBA] Spring Boot Admin Security 적용하기  (0) 2018.12.18
[SBA] Spring Boot Admin 띄워보기  (0) 2018.12.18

윈도우에서는 공식적으로 Redis 를 사용할 수 없지만 MSOpenTech에서 지속적으로


윈도우 버전으로 포팅을 해주고 있습니다. 현재 최신 버전은 3.2.100 입니다.


아래의 링크로 접속하여 다운받은 후 설치를 진행합니다.


https://github.com/MicrosoftArchive/redis/releases


여기서 zip 버전을 다운받은 후 원하는 위치에 압축을 해제합니다.


압축을 해제후 폴더로 접근하여 redis-server.exe를 실행하면 레디스가 실행이 됩니다.


그리고 Redis Client Tool로는 아래의 링크에서 받아서 사용하시기 바랍니다.


https://fastoredis.com/anonim_users_downloads

이전에 진행했던 Spring Boot Admin 띄워보기에 이어 여기에 Spring Security 까지 적용해보겠습니다.


(이전 글: https://dev-t-blog.tistory.com/26)


여기서 추가된것은 Gradle에 Srping Security 의존성하고


WebSecurityConfig 파일 그리고 application.yml이 조금 추가되었습니다.


Sprign Boot Admin 로그인 할때 데이터베이스를 이용할 수 도 있고, 인메모리 DB, application.yml에 값을 설정하여 여러가지고 사용할 수 있는데


현재 아래의 소스는 인메모리 DB로 진행하였습니다. 그래서 별도의 DB없이 바로 실행이 가능합니다.


해당 소스를 아래에 링크 걸어두었습니다.


구동방법은 이전 글에서 참조해주시기 바랍니다.


kbn-sample.zip

다운로드(클라이언트)


eda-sba.zip

다운로드(관리자)




eda-sba 구동후 http://localhost:8081/eda-sba/ 에 접속을 하시면 이와 같은 화면을 보실 수 있습니다.

'Spring' 카테고리의 다른 글

[logback] Log를 JSON 형식으로 출력하는 방법  (0) 2018.12.19
[SBA] Spring Boot Admin 띄워보기  (0) 2018.12.18

스프링으로 웹 어플리케이션을 개발하다보면 해당 웹 어플리케이션을 모니터링 해야할 때가 있습니다.


별도의 유료의 모니터링 시스템을 갖춘 회사라면 상관이 없지만 


현재 필요한것은 무료 모니터링 시스템을 갖추는 것입니다.

(회사에서 안사줘서.....)


스프링 진영에서 무료로 사용할 수 있는 모니터링 프로젝트가 있습니다.


프로젝트는 Spring Boot Admin 입니다.

(Git URL: https://github.com/codecentric/spring-boot-admin)


이 프로젝트를 이용해서 손쉽게 모니터링 시스템을 갖출 수 있습니다.


해당 예제 소스는 첨부파일로 첨부하였습니다.


사전에 설치할 프로그램은


Maven, Java 1.8 이상, Gradle, IDE IntelliJ 입니다.


kbn-sample.zip

클릭하여 다운로드



eda-sba.zip

클릭하여 다운로드



위의 소스를 받은 후 IntelliJ에서 프로젝트를 Import 후 


eda-sba 를 먼저 Start 시켜준 후 kbn-sample Start를 시키면 됩니다.


그리고 웹 브라우저에서 http://localhost:8081/eda-sba 에 접근 하시면 됩니다.


접근을 하게 되면 아래와 같은 화면이 나옵니다. 


그리고 상단의 wallboard 를 클릭 후 화면에 나오는 6각형 도형을 클릭하면 해당 어플리케이션의 자세한 현황이 나옵니다.


마지막으로 Spring Security 를 이용하면 Spring Boot Admin 에 로그인 기능도 추가가 가능하며 그 외의 인증들도 사용이 가능합니다.


해당 예제 프로젝트는 Security 없이 동작하는 예제 입니다.




Spring Boot Admin http://localhost:8081/eda-sba/ 에 접속한 첫 화면 입니다.





상단의 Wallboard 접근 후 6각형 도형을 클릭 후 현재 어플리케이션의 상태를 실시간으로 확인하는 화면 입니다.



Threejs 의 OBJLoader(.obj 모델링 파일 가능) 를 이용하여 3D로 모델링 파일 로드를 할 수 있습니다.


여기에 텍스쳐를 입혀서 모델링을 좀더 꾸며 보겠습니다.


Material 이란? 오브젝트에 적용할 수 있는 색상? 페인트? 같은 개념입니다.

Texture란? 3D 모델에 입힐 이미지 파일 입니다. Texture를 사용하려면 중간에 Material 매개체가 필요합니다.


※ 참고: 해당 소스를 구동시 Local에서 실행하게 되면 Cross Origin 오류가 발생하니 크롬 확장 프로그램인 Web Server for Chrome를 받아서


해당 소스를 다운받은 크롬 확장 프로그램으로 서버를 돌려서 확인 하거나 Web Server에 소스를 업로드하여 구동하시기 바랍니다.


무료 모델링 소스는 https://free3d.com/3d-models/animals 에서 받아서 다른 모델링도 적용할 수 있습니다.



obj-mtl-loader.zip

↑↑↑↑↑↑↑↑↑↑

소스파일 다운로드 입니다.


<!DOCTYPE html>
<html>

<head>
    <meta charset=utf-8>
    <title>My first three.js app</title>
    <style>
        body {
            margin: 0;
        }

        canvas {
            width: 100%;
            height: 100%
        }
    </style>
</head>

<body>
    <!-- Three js -->
    <script src="https://threejs.org/build/three.min.js"></script>

    <!-- WebGL 지원유무 https://github.com/mrdoob/three.js/blob/master/examples/js/WebGL.js 참고 -->
    <script src="./libs/WebGL.js"></script>

    <!-- OrbitControls.js allow the camera to orbit around a target 마우스와 카메라를 상호작용하게 합니다. -->
    <script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

    <!-- OBJ Loader를 사용하기 위해 추가. https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/OBJLoader.js 와 동일 소스 -->
    <script src="./libs/OBJLoader.js"></script>

    <!-- OBJ Loader에 Material을 씌우기 위한 라이브러리 추가. https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/MTLLoader.js 와 동일 소스 -->
    <script src="./libs/MTLLoader.js"></script>

    <script>
        window.onload = function (e) {

            let scene = new THREE.Scene();
            let light;
            let camera;
            let objLoader; // OBJLoader 객체를 넣을 변수를 선언합니다.
            let mtlLoader; // MTLLoader 객체를 넣을 변수를 선언합니다.

            initThree();
            addDirectionalLight();
            loadMTLLoader();

            /**
             * DirectionalLight를 추가하는 함수
             *
             * @method addDirectionalLight
             */
            function addDirectionalLight() {
                let light1 = new THREE.DirectionalLight(0xffffff, 1);
                light1.position.set(-100, 0, 100);
                let light2 = new THREE.DirectionalLight(0xffffff, 1);
                light2.position.set(100, 0, 100);
                let light3 = new THREE.DirectionalLight(0xffffff, 1);
                light3.position.set(100, 0, -100);
                scene.add(light1);
                scene.add(light2);
                scene.add(light3);
            }

            /**
             * Material 파일을 로드하는 함수
             *
             * @method loadMTLLoader
             */
            function loadMTLLoader() {
                mtlLoader = new THREE.MTLLoader();

                // MTLLoader Material 파일을 사용할 전역 경로를 설정합니다.
                mtlLoader.setPath('./resources/Umbreon/');

                // 로드할 Material 파일 명을 입력합니다.
                mtlLoader.load('UmbreonHighPoly.mtl', function (materials) {
                    // 로드 완료되었을때 호출하는 함수
                    materials.preload();

                    loadOBJLoader(materials);
                }, function (xhr) {
                    // 로드되는 동안 호출되는 함수
                    console.log('MTLLoader: ', xhr.loaded / xhr.total * 100, '% loaded');
                }, function (error) {
                    // 로드가 실패했을때 호출하는 함수
                    console.error('MTLLoader 로드 중 오류가 발생하였습니다.', error);
                    alert('MTLLoader 로드 중 오류가 발생하였습니다.');
                });
            }

            /**
             * .obj 파일의 모델을 로드하는 함수
             *
             * @method loadObjLoader
             * @param {Object} materials MTLLoader에서 로드한 Materials 값
             */
            function loadOBJLoader(materials) {
                loader = new THREE.OBJLoader();

                // MTLLoader에서 로드한 materials 파일을 설정합니다.
                loader.setMaterials(materials);

                // OBJLoader OBJ 파일을 사용할 전역 경로를 설정합니다.
                loader.setPath('./resources/Umbreon/');

                // 로드할 OBJ 파일 명을 입력합니다.
                loader.load('UmbreonHighPoly.obj', function (object) {
                    // 모델 로드가 완료되었을때 호출되는 함수
                    object.position.x = 0;
                    object.position.y = 0;
                    object.position.z = 0;
                    scene.add(object);
                }, function (xhr) {
                    // 모델이 로드되는 동안 호출되는 함수
                    console.log('OBJLoader: ', xhr.loaded / xhr.total * 100, '% loaded');
                }, function (error) {
                    // 모델 로드가 실패했을 때 호출하는 함수
                    alert('모델을 로드 중 오류가 발생하였습니다.');
                });
            }

            /**
             * Threejs 초기화 함수
             *
             * @method initThree
             */
            function initThree() {
                // 브라우저가 WebGL을 지원하는지 체크
                if (WEBGL.isWebGLAvailable()) {
                    console.log('이 브라우저는 WEBGL을 지원합니다.');
                } else {
                    console.log('이 브라우저는 WEBGL을 지원하지 않습니다.');
                }

                camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);

                let renderer = new THREE.WebGLRenderer({
                    antialias: true
                });
                renderer.setSize(window.innerWidth, window.innerHeight);
                renderer.setClearColor(0xffffff, 1); // 전체적인 배경색 수정
                renderer.shadowMap.enabled = true;
                renderer.shadowMap.type = THREE.PCFSoftShadowMap;
                document.body.appendChild(renderer.domElement);

                let axes = new THREE.AxisHelper(10);
                scene.add(axes);

                camera.position.x = 1;
                camera.position.y = 3;
                camera.position.z = 3;

                controls = new THREE.OrbitControls(camera);
                controls.rotateSpeed = 1.0;
                controls.zoomSpeed = 1.2;
                controls.panSpeed = 0.8;
                controls.minDistance = 3;
                controls.maxDistance = 10;

                function animate() {
                    requestAnimationFrame(animate);

                    renderer.render(scene, camera);
                    controls.update();
                }

                animate();
            }
        }
    </script>
</body>

</html>


+ Recent posts