Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d97b7e679f | ||
|
|
530477fb75 | ||
|
|
6a78475844 | ||
|
|
8a4b8e49f1 | ||
|
|
235ea7143a | ||
|
|
520d2df3a9 | ||
|
|
3b0803bef3 | ||
|
|
7d17b8d617 | ||
|
|
c51608276d | ||
|
|
f8c6c83c96 | ||
|
|
27ce3cc9ed | ||
|
|
1d9d35d7c0 | ||
|
|
adec554122 | ||
|
|
c64d4b1b07 |
@@ -0,0 +1,17 @@
|
|||||||
|
name: Test Workflow
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Print environment variables
|
||||||
|
run: |
|
||||||
|
echo "GITHUB_REPOSITORY: $GITHUB_REPOSITORY"
|
||||||
|
echo "GITHUB_SHA: $GITHUB_SHA"
|
||||||
|
echo "GITHUB_REF: $GITHUB_REF"
|
||||||
|
echo "GITHUB_ACTOR: $GITHUB_ACTOR"
|
||||||
|
echo "PATH: $PATH"
|
||||||
+92
-1
@@ -29,5 +29,96 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "8080:8080"
|
- "8080:8080"
|
||||||
|
|
||||||
|
grafana:
|
||||||
|
image: grafana/grafana:10.3.1
|
||||||
|
container_name: grafana
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
depends_on:
|
||||||
|
prometheus:
|
||||||
|
condition: service_healthy
|
||||||
|
loki:
|
||||||
|
condition: service_healthy
|
||||||
|
tempo:
|
||||||
|
condition: service_started
|
||||||
|
alloy:
|
||||||
|
condition: service_started
|
||||||
|
environment:
|
||||||
|
GF_AUTH_ANONYMOUS_ENABLED: "true"
|
||||||
|
GF_SECURITY_ADMIN_USER: admin
|
||||||
|
GF_SECURITY_ADMIN_PASSWORD: admin
|
||||||
|
GF_METRICS_ENABLED: "true"
|
||||||
|
volumes:
|
||||||
|
- ./infrastructure/grafana/provisioning:/etc/grafana/provisioning
|
||||||
|
- ./infrastructure/grafana/dashboards:/var/lib/grafana/dashboards
|
||||||
|
healthcheck:
|
||||||
|
test: [ "CMD", "wget", "--spider", "http://localhost:3000/api/health" ]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 10
|
||||||
|
|
||||||
|
prometheus:
|
||||||
|
image: prom/prometheus:latest
|
||||||
|
container_name: prometheus
|
||||||
|
ports:
|
||||||
|
- "9090:9090"
|
||||||
|
volumes:
|
||||||
|
- ./infrastructure/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
|
||||||
|
healthcheck:
|
||||||
|
test: [ "CMD", "wget", "--spider", "http://localhost:9090/-/healthy" ]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
loki:
|
||||||
|
image: grafana/loki:2.9.2
|
||||||
|
container_name: loki
|
||||||
|
ports:
|
||||||
|
- "3100:3100"
|
||||||
|
volumes:
|
||||||
|
- ./infrastructure/loki/loki-config.yaml:/etc/loki/loki-config.yaml:ro
|
||||||
|
healthcheck:
|
||||||
|
test: [ "CMD", "wget", "--spider", "-q", "http://localhost:3100/ready" ]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
tempo:
|
||||||
|
image: grafana/tempo:2.4.1
|
||||||
|
container_name: tempo
|
||||||
|
command: [ "-config.file=/etc/tempo/tempo.yaml" ]
|
||||||
|
volumes:
|
||||||
|
- ./infrastructure/tempo/tempo.yaml:/etc/tempo/tempo.yaml
|
||||||
|
- tempo_data:/var/tempo
|
||||||
|
ports:
|
||||||
|
- "3200:3200"
|
||||||
|
|
||||||
|
alloy:
|
||||||
|
image: grafana/alloy:latest
|
||||||
|
container_name: alloy
|
||||||
|
user: root
|
||||||
|
ports:
|
||||||
|
- "9080:9080" # HTTP interface
|
||||||
|
- "4317:4317" # OTLP gRPC
|
||||||
|
- "4318:4318" # OTLP http
|
||||||
|
volumes:
|
||||||
|
- ./infrastructure/alloy/config.alloy:/etc/alloy/config.alloy:ro
|
||||||
|
- /var/lib/docker/containers:/var/lib/docker/containers:ro
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
- /var/log:/var/log:ro
|
||||||
|
environment:
|
||||||
|
GRAFANA_LOKI_URL: http://loki:3100/loki/api/v1/push
|
||||||
|
command:
|
||||||
|
- run
|
||||||
|
- --server.http.listen-addr=0.0.0.0:9080
|
||||||
|
- --storage.path=/var/lib/alloy/data
|
||||||
|
- /etc/alloy/config.alloy
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
pgdata:
|
pgdata:
|
||||||
|
artifacts:
|
||||||
|
tempo_data:
|
||||||
|
loki_data:
|
||||||
|
loki_chunks:
|
||||||
|
loki_index:
|
||||||
|
loki_rules:
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
loki.write "local" {
|
||||||
|
endpoint {
|
||||||
|
url = "http://loki:3100/loki/api/v1/push"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
discovery.docker "containers" {
|
||||||
|
host = "unix:///var/run/docker.sock"
|
||||||
|
refresh_interval = "5s"
|
||||||
|
}
|
||||||
|
|
||||||
|
discovery.relabel "containers" {
|
||||||
|
targets = discovery.docker.containers.targets
|
||||||
|
|
||||||
|
rule {
|
||||||
|
source_labels = ["__meta_docker_container_name"]
|
||||||
|
regex = "/(.*)"
|
||||||
|
target_label = "container"
|
||||||
|
}
|
||||||
|
|
||||||
|
rule {
|
||||||
|
target_label = "job"
|
||||||
|
replacement = "docker"
|
||||||
|
}
|
||||||
|
|
||||||
|
rule {
|
||||||
|
target_label = "host"
|
||||||
|
replacement = constants.hostname
|
||||||
|
}
|
||||||
|
|
||||||
|
rule {
|
||||||
|
source_labels = ["__meta_docker_container_name"]
|
||||||
|
regex = "/(.*)"
|
||||||
|
target_label = "service"
|
||||||
|
}
|
||||||
|
|
||||||
|
rule {
|
||||||
|
source_labels = ["__meta_docker_container_log_stream"]
|
||||||
|
target_label = "stream"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loki.source.docker "containers" {
|
||||||
|
host = "unix:///var/run/docker.sock"
|
||||||
|
targets = discovery.docker.containers.targets
|
||||||
|
relabel_rules = discovery.relabel.containers.rules
|
||||||
|
forward_to = [loki.write.local.receiver]
|
||||||
|
}
|
||||||
|
|
||||||
|
otelcol.receiver.otlp "default" {
|
||||||
|
grpc {
|
||||||
|
endpoint = "0.0.0.0:4317"
|
||||||
|
}
|
||||||
|
http {
|
||||||
|
endpoint = "0.0.0.0:4318"
|
||||||
|
}
|
||||||
|
output {
|
||||||
|
traces = [otelcol.exporter.otlp.tempo.input]
|
||||||
|
metrics = [otelcol.exporter.prometheus.default.input]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
otelcol.exporter.otlp "tempo" {
|
||||||
|
client {
|
||||||
|
endpoint = "tempo:4317"
|
||||||
|
tls {
|
||||||
|
insecure = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
otelcol.exporter.prometheus "default" {
|
||||||
|
forward_to = []
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
"title": "Postgres Overview",
|
||||||
|
"timezone": "browser",
|
||||||
|
"schemaVersion": 39,
|
||||||
|
"version": 1,
|
||||||
|
"refresh": "10s",
|
||||||
|
"panels": [
|
||||||
|
{
|
||||||
|
"type": "gauge",
|
||||||
|
"title": "pg_up",
|
||||||
|
"targets": [{ "expr": "pg_up", "refId": "A" }],
|
||||||
|
"gridPos": { "x": 0, "y": 0, "w": 4, "h": 6 }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "timeseries",
|
||||||
|
"title": "Active sessions by state",
|
||||||
|
"targets": [
|
||||||
|
{ "expr": "sum by (state,instance) (pg_stat_activity_count)", "refId": "A" }
|
||||||
|
],
|
||||||
|
"gridPos": { "x": 4, "y": 0, "w": 20, "h": 6 }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "timeseries",
|
||||||
|
"title": "Transactions per second (commits+rollbacks)",
|
||||||
|
"targets": [
|
||||||
|
{ "expr": "sum(rate(pg_stat_database_xact_commit[1m])) + sum(rate(pg_stat_database_xact_rollback[1m]))", "refId": "A" }
|
||||||
|
],
|
||||||
|
"gridPos": { "x": 0, "y": 6, "w": 12, "h": 8 }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "timeseries",
|
||||||
|
"title": "Tuples fetched/returned/inserted/updated/deleted",
|
||||||
|
"targets": [
|
||||||
|
{ "expr": "sum(rate(pg_stat_database_tup_fetched[1m]))", "legendFormat": "fetched", "refId": "A" },
|
||||||
|
{ "expr": "sum(rate(pg_stat_database_tup_returned[1m]))", "legendFormat": "returned", "refId": "B" },
|
||||||
|
{ "expr": "sum(rate(pg_stat_database_tup_inserted[1m]))", "legendFormat": "inserted", "refId": "C" },
|
||||||
|
{ "expr": "sum(rate(pg_stat_database_tup_updated[1m]))", "legendFormat": "updated", "refId": "D" },
|
||||||
|
{ "expr": "sum(rate(pg_stat_database_tup_deleted[1m]))", "legendFormat": "deleted", "refId": "E" }
|
||||||
|
],
|
||||||
|
"gridPos": { "x": 12, "y": 6, "w": 12, "h": 8 }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
apiVersion: 1
|
||||||
|
|
||||||
|
datasources:
|
||||||
|
- name: Prometheus
|
||||||
|
type: prometheus
|
||||||
|
access: proxy
|
||||||
|
url: http://prometheus:9090
|
||||||
|
isDefault: true
|
||||||
|
- name: Loki
|
||||||
|
type: loki
|
||||||
|
access: proxy
|
||||||
|
url: http://loki:3100
|
||||||
|
isDefault: false
|
||||||
|
editable: true
|
||||||
|
- name: Tempo
|
||||||
|
type: tempo
|
||||||
|
access: proxy
|
||||||
|
url: http://tempo:3200
|
||||||
|
isDefault: false
|
||||||
|
editable: true
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
apiVersion: 1
|
||||||
|
|
||||||
|
providers:
|
||||||
|
- name: 'default'
|
||||||
|
folder: 'Individuals-api'
|
||||||
|
type: file
|
||||||
|
disableDeletion: false
|
||||||
|
editable: true
|
||||||
|
options:
|
||||||
|
path: /var/lib/grafana/dashboards
|
||||||
|
foldersFromFilesStructure: true
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
apiVersion: 1
|
||||||
|
|
||||||
|
datasources:
|
||||||
|
- name: Prometheus
|
||||||
|
type: prometheus
|
||||||
|
access: proxy
|
||||||
|
url: http://prometheus:9090
|
||||||
|
isDefault: true
|
||||||
|
- name: Loki
|
||||||
|
type: loki
|
||||||
|
access: proxy
|
||||||
|
url: http://loki:3100
|
||||||
|
isDefault: false
|
||||||
|
editable: true
|
||||||
|
- name: Tempo
|
||||||
|
type: tempo
|
||||||
|
access: proxy
|
||||||
|
url: http://tempo:3200
|
||||||
|
isDefault: false
|
||||||
|
editable: true
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
auth_enabled: false
|
||||||
|
|
||||||
|
server:
|
||||||
|
http_listen_post: 3100
|
||||||
|
|
||||||
|
ingester:
|
||||||
|
lifecycler:
|
||||||
|
address: 0.0.0.0
|
||||||
|
ring:
|
||||||
|
kvstore:
|
||||||
|
store: summary
|
||||||
|
replication_factor: 1
|
||||||
|
final_sleep: 0s
|
||||||
|
chunk_idle_period: 5m
|
||||||
|
chunk_retain_period: 30s
|
||||||
|
max_transfer_retries: 0
|
||||||
|
|
||||||
|
schema_config:
|
||||||
|
configs:
|
||||||
|
- from: 2018-04-15
|
||||||
|
store: boltdb
|
||||||
|
object_store: filesystem
|
||||||
|
schema: v11
|
||||||
|
index:
|
||||||
|
prefix: index_
|
||||||
|
period: 168h
|
||||||
|
|
||||||
|
storage_config:
|
||||||
|
boltdb:
|
||||||
|
directory: /loki/index
|
||||||
|
filesystem:
|
||||||
|
directory: /loki/chunks
|
||||||
|
|
||||||
|
limits_config:
|
||||||
|
enforce_metric_name: false
|
||||||
|
reject_old_samples: true
|
||||||
|
reject_old_samples_max_age: 168h
|
||||||
|
ingestion_rate_mb: 8
|
||||||
|
ingestion_burst_size_md: 10
|
||||||
|
|
||||||
|
chunk_storage_config:
|
||||||
|
max_look_back_period: 0s
|
||||||
|
|
||||||
|
table_manager:
|
||||||
|
chunk_tables_provisioning:
|
||||||
|
inactive_read_throughput: 0
|
||||||
|
inactive_write_throughput: 0
|
||||||
|
provisioned_read_throughput: 0
|
||||||
|
provisioned_write_throughput: 0
|
||||||
|
index_tables_provisioning:
|
||||||
|
inactive_read_throughput: 0
|
||||||
|
inactive_write_throughput: 0
|
||||||
|
provisioned_read_throughput: 0
|
||||||
|
provisioned_write_throughput: 0
|
||||||
|
retention_deletes_enabled: true
|
||||||
|
retention_period: 672h
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
global:
|
||||||
|
scrape_interval: 15s
|
||||||
|
scrape_timeout: 10s
|
||||||
|
evaluation_interval: 15s
|
||||||
|
|
||||||
|
|
||||||
|
scrape_configs:
|
||||||
|
- job_name: prometheus
|
||||||
|
static_configs:
|
||||||
|
- targets: [ "prometheus:9090" ]
|
||||||
|
|
||||||
|
- job_name: api
|
||||||
|
metrics_path: /actuator/prometheus
|
||||||
|
static_configs:
|
||||||
|
- targets: [ 'api:8091' ]
|
||||||
|
|
||||||
|
- job_name: persons-api
|
||||||
|
metrics_path: /actuator/prometheus
|
||||||
|
static_configs:
|
||||||
|
- targets: [ 'persons-api:8092' ]
|
||||||
|
|
||||||
|
- job_name: keycloak
|
||||||
|
metrics_path: /metrics
|
||||||
|
static_configs:
|
||||||
|
- targets: [ 'keycloak:9000' ]
|
||||||
|
|
||||||
|
- job_name: grafana
|
||||||
|
metrics_path: /metrics
|
||||||
|
static_configs:
|
||||||
|
- targets: [ 'grafana:3000' ]
|
||||||
|
|
||||||
|
- job_name: alloy
|
||||||
|
metrics_path: /metrics
|
||||||
|
static_configs:
|
||||||
|
- targets: [ 'alloy:9080' ]
|
||||||
|
|
||||||
|
- job_name: loki
|
||||||
|
metrics_path: /metrics
|
||||||
|
static_configs:
|
||||||
|
- targets: [ 'loki:3100' ]
|
||||||
|
|
||||||
|
- job_name: tempo
|
||||||
|
metrics_path: /metrics
|
||||||
|
static_configs:
|
||||||
|
- targets: [ 'tempo:3200' ]
|
||||||
|
|
||||||
|
- job_name: person-postgres
|
||||||
|
static_configs:
|
||||||
|
- targets: [ 'person-postgres-exporter:9187' ]
|
||||||
|
|
||||||
|
- job_name: keycloak-postgres
|
||||||
|
static_configs:
|
||||||
|
- targets: [ 'keycloak-postgres-exporter:9187' ]
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
server:
|
||||||
|
http_listen_port: 3200
|
||||||
|
|
||||||
|
distributor:
|
||||||
|
receivers:
|
||||||
|
otlp:
|
||||||
|
protocols:
|
||||||
|
grpc:
|
||||||
|
http:
|
||||||
|
|
||||||
|
ingester:
|
||||||
|
trace_idle_period: 10s
|
||||||
|
|
||||||
|
compactor:
|
||||||
|
compaction:
|
||||||
|
compacted_block_retention: 48h
|
||||||
|
|
||||||
|
storage:
|
||||||
|
trace:
|
||||||
|
backend: local
|
||||||
|
local:
|
||||||
|
path: /var/tempo/traces
|
||||||
@@ -3,10 +3,7 @@ package ru.soune.no_copy.controller;
|
|||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
import ru.soune.no_copy.dto.AuthResponse;
|
import ru.soune.no_copy.dto.AuthResponse;
|
||||||
import ru.soune.no_copy.dto.LoginRequest;
|
import ru.soune.no_copy.dto.LoginRequest;
|
||||||
import ru.soune.no_copy.dto.LoginResponse;
|
import ru.soune.no_copy.dto.LoginResponse;
|
||||||
@@ -14,6 +11,8 @@ import ru.soune.no_copy.dto.RegisterRequest;
|
|||||||
import ru.soune.no_copy.entity.AuthToken;
|
import ru.soune.no_copy.entity.AuthToken;
|
||||||
import ru.soune.no_copy.service.AuthService;
|
import ru.soune.no_copy.service.AuthService;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/auth")
|
@RequestMapping("/api/auth")
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@@ -36,4 +35,13 @@ public class AuthController {
|
|||||||
return ResponseEntity.ok(new LoginResponse(true, login.getUser().getEmail(),
|
return ResponseEntity.ok(new LoginResponse(true, login.getUser().getEmail(),
|
||||||
login.getToken(),login.getExpiresAt().toString()));
|
login.getToken(),login.getExpiresAt().toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/logout")
|
||||||
|
public ResponseEntity<?> logout(@RequestHeader("Authorization") String tokenHeader) {
|
||||||
|
String token = tokenHeader.replace("Bearer ", "");
|
||||||
|
|
||||||
|
authService.logout(token);
|
||||||
|
|
||||||
|
return ResponseEntity.ok(Map.of("success", true));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package ru.soune.no_copy.controller;
|
||||||
|
|
||||||
|
import org.apache.coyote.Response;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api")
|
||||||
|
public class HealtCheckController {
|
||||||
|
|
||||||
|
@GetMapping("/healt")
|
||||||
|
public HttpStatus healtCheck() {
|
||||||
|
return HttpStatus.OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,4 +10,5 @@ import java.util.Optional;
|
|||||||
@Repository
|
@Repository
|
||||||
public interface AuthTokenRepository extends JpaRepository<AuthToken, Long> {
|
public interface AuthTokenRepository extends JpaRepository<AuthToken, Long> {
|
||||||
Optional<AuthToken> findByTokenAndExpiresAtAfter(String token, LocalDate expiresAtAfter);
|
Optional<AuthToken> findByTokenAndExpiresAtAfter(String token, LocalDate expiresAtAfter);
|
||||||
|
Optional<AuthToken> findByToken(String token);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,6 +78,10 @@ public class AuthService {
|
|||||||
return authTokenRepository.save(authToken);
|
return authTokenRepository.save(authToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void logout(String token) {
|
||||||
|
authTokenRepository.findByToken(token)
|
||||||
|
.ifPresent(authTokenRepository::delete);
|
||||||
|
}
|
||||||
|
|
||||||
private String generateAuthToken() {
|
private String generateAuthToken() {
|
||||||
byte[] bytes = new byte[32];
|
byte[] bytes = new byte[32];
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE configuration>
|
||||||
|
|
||||||
|
<configuration scan="true">
|
||||||
|
|
||||||
|
<statusListener class="ch.qos.logback.core.status.NopStatusListener"/>
|
||||||
|
|
||||||
|
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<encoder>
|
||||||
|
<pattern>{"timestamp":"%d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX}", "trace_id": "%X{trace_id}",
|
||||||
|
"span_id":"%X{span_id}", "level":"%level", "thread":"%thread",
|
||||||
|
"logger":"%logger{36}","message":"%msg"}%n
|
||||||
|
</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<root level="INFO">
|
||||||
|
<appender-ref ref="console"/>
|
||||||
|
</root>
|
||||||
|
|
||||||
|
</configuration>
|
||||||
Reference in New Issue
Block a user