diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index a741b064..cb187bba 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -53,10 +53,10 @@ jobs: run: echo "##[set-output name=version;]$(echo '${{ github.event.head_commit.message }}' | egrep -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')" id: extract_version_name - - name: push + - name: build and push api server uses: docker/build-push-action@v4 with: - context: . + context: ./deploy/api platforms: linux/arm64/v8 push: true tags: | @@ -69,6 +69,7 @@ jobs: "REDIS_HOST=${{ secrets.REDIS_HOST }}" "REDIS_PORT=${{ secrets.REDIS_PORT }}" "INTERNAL_SECRET=${{ secrets.INTERNAL_SECRET }}" + "SLACK_TOKEN=${{ secrets.SLACK_TOKEN }}" deploy: needs: build @@ -79,8 +80,34 @@ jobs: run: echo "##[set-output name=version;]$(echo '${{ github.event.head_commit.message }}' | egrep -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')" id: extract_version_name - - name: run server + - name: run api server run: | sudo docker pull ghcr.io/devxb/gitanimals:${{ steps.extract_version_name.outputs.version }} sudo docker ps -q --filter "expose=8080" | xargs sudo docker stop | xargs sudo docker rm - sudo docker run -d -p 8081:8080 ghcr.io/devxb/gitanimals:${{ steps.extract_version_name.outputs.version }} + sudo docker run -d -p 8081:8080 -v logs:/logs ghcr.io/devxb/gitanimals:${{ steps.extract_version_name.outputs.version }} + + - name: check filebeat status + id: check-status + run: | + if docker ps --filter "name=filebeat" --filter "status=running" --format "{{.Names}}" | grep -q "^filebeat$"; then + echo "Filebeat is already running" + echo "status=running" >> $GITHUB_ENV + else + echo "Filebeat is not running" + echo "status=stopped" >> $GITHUB_ENV + fi + + - name: display filebeat status + run: | + if [ "${{ env.status }}" == "running" ]; then + echo "✅ Filebeat is already running" + else + echo "🚀 Filebeat is not running. Starting deployment..." + fi + + - name: run file beats + if: env.status == 'running' + run: | + docker build -t filebeat-gitanimals:latest ./deploy/filebeat + docker run -d --name filebeat -v logs:/logs -t filebeat-gitanimals:latest + diff --git a/.gitignore b/.gitignore index ac03c439..629ff5ec 100644 --- a/.gitignore +++ b/.gitignore @@ -42,3 +42,4 @@ bin/ .DS_Store .idea +logs diff --git a/build.gradle b/build.gradle index c811a92b..6fd77667 100644 --- a/build.gradle +++ b/build.gradle @@ -37,6 +37,8 @@ sentry { apply from: "gradle/db.gradle" apply from: "gradle/core.gradle" apply from: "gradle/test.gradle" +apply from: "gradle/slack.gradle" apply from: "gradle/spring.gradle" apply from: "gradle/monitor.gradle" +apply from: "gradle/logging.gradle" apply from: "gradle/jetbrains.gradle" diff --git a/Dockerfile b/deploy/api/Dockerfile similarity index 76% rename from Dockerfile rename to deploy/api/Dockerfile index e53a500d..1f969145 100644 --- a/Dockerfile +++ b/deploy/api/Dockerfile @@ -7,8 +7,9 @@ ARG GITHUB_TOKEN ARG REDIS_HOST ARG REDIS_PORT ARG INTERNAL_SECRET +ARG SLACK_TOKEN -ARG JAR_FILE=./build/libs/*.jar +ARG JAR_FILE=../../build/libs/*.jar COPY ${JAR_FILE} gitanimals-render.jar ENV db_url=${DB_URL} \ @@ -17,7 +18,8 @@ ENV db_url=${DB_URL} \ github_token=${GITHUB_TOKEN} \ redis_host=${REDIS_HOST} \ redis_port=${REDIS_PORT} \ - internal_secret=${INTERNAL_SECRET} + internal_secret=${INTERNAL_SECRET} \ + slack_token=${SLACK_TOKEN} ENTRYPOINT java -jar gitanimals-render.jar \ --spring.datasource.url=${db_url} \ @@ -26,4 +28,5 @@ ENTRYPOINT java -jar gitanimals-render.jar \ --netx.host=${redis_host} \ --netx.port=${redis_port} \ --github.token=${github_token} \ - --internal.secret=${internal_secret} + --internal.secret=${internal_secret} \ + --slack.token=${slack_token} diff --git a/deploy/filebeat/Dockerfile b/deploy/filebeat/Dockerfile new file mode 100644 index 00000000..2f6a53df --- /dev/null +++ b/deploy/filebeat/Dockerfile @@ -0,0 +1,16 @@ +# Filebeat Base Image +FROM docker.elastic.co/beats/filebeat:8.10.0 + +# Copy custom Filebeat configuration +COPY filebeat.yml /usr/share/filebeat/filebeat.yml + +# Set permissions +USER root +RUN chmod go-w /usr/share/filebeat/filebeat.yml + +# Set working directory +WORKDIR /usr/share/filebeat + +# Entry point +ENTRYPOINT ["filebeat"] +CMD ["-e", "-c", "/usr/share/filebeat/filebeat.yml"] diff --git a/deploy/filebeat/filebeat.yml b/deploy/filebeat/filebeat.yml new file mode 100644 index 00000000..c4682b42 --- /dev/null +++ b/deploy/filebeat/filebeat.yml @@ -0,0 +1,18 @@ +filebeat.inputs: + - type: log + enabled: true + paths: + - ./logs/*.json + json: + keys_under_root: true + add_error_key: true + +output.elasticsearch: + hosts: ["192.168.0.31:9200"] + username: "elastic" + password: "" + +processors: + - decode_json_fields: + fields: ["message"] + target: "" diff --git a/gradle.properties b/gradle.properties index 5cbd249e..51dfe99b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -40,3 +40,9 @@ snowflakeVersion=5.2.5 ### Caffeine cache ### caffeineCacheVersion=3.1.8 + +### Ecs logback encoder ### +logbackEcsEncoderVersion=1.6.0 + +### Slack ### +slackVersion=1.40.2 diff --git a/gradle/logging.gradle b/gradle/logging.gradle new file mode 100644 index 00000000..53f44a06 --- /dev/null +++ b/gradle/logging.gradle @@ -0,0 +1,3 @@ +dependencies { + implementation "co.elastic.logging:logback-ecs-encoder:${logbackEcsEncoderVersion}" +} diff --git a/gradle/slack.gradle b/gradle/slack.gradle new file mode 100644 index 00000000..6eac8119 --- /dev/null +++ b/gradle/slack.gradle @@ -0,0 +1,5 @@ +dependencies { + implementation "com.slack.api:bolt:${slackVersion}" + implementation "com.slack.api:bolt-servlet:${slackVersion}" + implementation "com.slack.api:bolt-jetty:${slackVersion}" +} diff --git a/src/main/kotlin/org/gitanimals/core/appender/SlackAppender.kt b/src/main/kotlin/org/gitanimals/core/appender/SlackAppender.kt new file mode 100644 index 00000000..ede0e9a6 --- /dev/null +++ b/src/main/kotlin/org/gitanimals/core/appender/SlackAppender.kt @@ -0,0 +1,44 @@ +package org.gitanimals.core.appender + +import ch.qos.logback.classic.Level +import ch.qos.logback.classic.spi.ILoggingEvent +import ch.qos.logback.core.AppenderBase +import com.slack.api.Slack +import com.slack.api.methods.MethodsClient +import com.slack.api.methods.request.chat.ChatPostMessageRequest + +class SlackAppender : AppenderBase() { + + lateinit var slack: MethodsClient + + private val errorChannel = "C080GR85WM9" + private val warnChannel = "C08977RL38C" + + override fun append(eventObject: ILoggingEvent) { + runCatching { + val channel = when (eventObject.level) { + Level.WARN -> warnChannel + Level.ERROR -> errorChannel + else -> NOT_LOGGING + } + + if (channel == NOT_LOGGING) { + return + } + + val request: ChatPostMessageRequest = ChatPostMessageRequest.builder() + .channel(channel) + .text(eventObject.formattedMessage) + .build(); + slack.chatPostMessage(request) + } + } + + fun setToken(token: String) { + this.slack = Slack.getInstance().methods(token) + } + + companion object { + private const val NOT_LOGGING = "NOT LOGGING" + } +} diff --git a/src/main/kotlin/org/gitanimals/render/controller/AnimationController.kt b/src/main/kotlin/org/gitanimals/render/controller/AnimationController.kt index 540a1920..00f155ef 100644 --- a/src/main/kotlin/org/gitanimals/render/controller/AnimationController.kt +++ b/src/main/kotlin/org/gitanimals/render/controller/AnimationController.kt @@ -3,6 +3,7 @@ package org.gitanimals.render.controller import jakarta.servlet.http.HttpServletResponse import org.gitanimals.render.app.AnimationFacade import org.gitanimals.core.Mode +import org.slf4j.LoggerFactory import org.springframework.http.HttpHeaders import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PathVariable @@ -14,6 +15,13 @@ class AnimationController( private val animationFacade: AnimationFacade, ) { + private val logger = LoggerFactory.getLogger(this::class.simpleName) + + @GetMapping("/for-logging-test") + fun forLoggingTest() { + logger.warn("For logging test") + } + @GetMapping(value = ["/farms/{username}"], produces = ["image/svg+xml"]) fun getFarmSvgAnimation( @PathVariable("username") username: String, diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 653540c2..c5aed7d6 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -21,6 +21,7 @@ netx.orphan-milli=60000 netx.backpressure=40 netx.logging.level=info +slack.token=xoxb- github.token=a sentry.dsn=https://fe1aaf784ec135343909a4a0dfe4f0eb@o4505051656486912.ingest.us.sentry.io/4507088960684032 @@ -31,3 +32,5 @@ internal.secret=a spring.application.name=render.gitanimals management.endpoints.web.exposure.include=prometheus management.metrics.tags.application=${spring.application.name} + +logging.level.root=WARN diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 00000000..2de089f9 --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + ${LOG_PATTERN} + + + + + + ${SERVICE_NAME} + + ${LOG_PATH}/${LOG_FILE}.json + + ${LOG_PATH}/${LOG_FILE}.json.%d{yyyy-MM-dd}.gz + ${MAX_HISTORY} + + + + + + + + + + + + + + + + + + + + + +