Skip to content

Commit 9809fdd

Browse files
authored
Merge pull request #164 from CleanEngine/dev
Dev
2 parents f0b6e27 + 6aa73ed commit 9809fdd

File tree

15 files changed

+264
-53
lines changed

15 files changed

+264
-53
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,6 @@ out/
3939
### 로컬 환경변수 ###
4040
local.properties
4141
/logs
42-
docker-compose.override.yml
42+
43+
docker-compose.override.yml
44+
opentelemetry-javaagent.jar

build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ dependencies {
5757
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.8'
5858
implementation 'org.springframework.boot:spring-boot-starter-actuator'
5959
implementation 'io.micrometer:micrometer-registry-prometheus'
60+
implementation("io.opentelemetry.instrumentation:opentelemetry-instrumentation-annotations:2.16.0")
6061

6162
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
6263
implementation 'com.google.code.gson:gson:2.13.1'

monitoring/docker-compose.yml

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
version: '3.8'
2+
3+
services:
4+
app:
5+
image: eclipse-temurin:21-jre-alpine
6+
container_name: my-spring-app2
7+
volumes:
8+
- ../build/libs/coin-0.0.1-SNAPSHOT.jar:/app/coin-0.0.1-SNAPSHOT.jar
9+
- /etc/localtime:/etc/localtime:ro
10+
- ./opentelemetry-javaagent.jar:/app/opentelemetry-javaagent.jar
11+
working_dir: /app
12+
command: [ "java", "-jar", "coin-0.0.1-SNAPSHOT.jar", "--spring.profiles.active=dev,mariadb-local,actuator,apm" ]
13+
ports:
14+
- "8080:8080"
15+
env_file:
16+
- ../docker/local.properties
17+
environment:
18+
- TZ=Asia/Seoul
19+
- OTEL_SERVICE_NAME=my-spring-app
20+
- OTEL_TRACES_EXPORTER=otlp
21+
- OTEL_EXPORTER_OTLP_ENDPOINT=http://jaeger:4318
22+
- OTEL_LOGS_EXPORTER=none
23+
- OTEL_METRICS_EXPORTER=none
24+
- OTEL_INSTRUMENTATION_METHODS_ENABLED=true
25+
- JAVA_TOOL_OPTIONS=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005, -javaagent:/app/opentelemetry-javaagent.jar
26+
depends_on:
27+
mariadb:
28+
condition: service_healthy
29+
networks:
30+
- app-network
31+
- monitoring-net
32+
33+
mariadb:
34+
image: mariadb:latest
35+
container_name: mariadb2
36+
ports:
37+
- "3306:3306"
38+
env_file:
39+
- ../docker/local.properties
40+
environment:
41+
- TZ=Asia/Seoul
42+
volumes:
43+
- mariadb_data:/var/lib/mysql
44+
- ../docker/mariadb/init.sql:/docker-entrypoint-initdb.d/init.sql
45+
healthcheck:
46+
test: [ "CMD", "healthcheck.sh", "--connect", "--innodb_initialized" ]
47+
interval: 10s
48+
timeout: 5s
49+
retries: 10
50+
networks:
51+
- app-network
52+
- monitoring-net
53+
54+
prometheus:
55+
image: prom/prometheus:v2.53.0
56+
container_name: prometheus
57+
volumes:
58+
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
59+
- prometheus_data:/prometheus
60+
command:
61+
- '--config.file=/etc/prometheus/prometheus.yml'
62+
- '--storage.tsdb.retention.time=30d'
63+
ports:
64+
- "9090:9090"
65+
networks:
66+
- monitoring-net
67+
restart: unless-stopped
68+
69+
grafana:
70+
image: grafana/grafana:11.0.0
71+
container_name: grafana
72+
volumes:
73+
- grafana_data:/var/lib/grafana
74+
- ./grafana/provisioning:/etc/grafana/provisioning
75+
ports:
76+
- "3000:3000"
77+
networks:
78+
- monitoring-net
79+
restart: unless-stopped
80+
depends_on:
81+
- prometheus
82+
- jaeger
83+
84+
jaeger:
85+
image: jaegertracing/all-in-one:latest
86+
container_name: jaeger
87+
ports:
88+
- "16686:16686"
89+
- "4317:4317"
90+
- "4318:4318"
91+
networks:
92+
- monitoring-net
93+
94+
volumes:
95+
prometheus_data: {}
96+
grafana_data: {}
97+
mariadb_data:
98+
driver: local
99+
100+
networks:
101+
app-network:
102+
name: app-network
103+
driver: bridge
104+
monitoring-net:
105+
name: monitoring-net
106+
driver: bridge
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
apiVersion: 1
2+
3+
datasources:
4+
- name: Prometheus
5+
type: prometheus
6+
url: http://prometheus:9090
7+
access: proxy
8+
isDefault: true
9+
editable: true
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
global:
2+
scrape_interval: 10s
3+
4+
scrape_configs:
5+
- job_name: 'prometheus'
6+
static_configs:
7+
- targets: ['prometheus:9090']
8+
- job_name: 'my-app'
9+
static_configs:
10+
- targets: [ 'app:8080' ]
11+
metrics_path: /actuator/prometheus
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.cleanengine.coin.common.annotation;
2+
3+
import java.lang.annotation.ElementType;
4+
import java.lang.annotation.Retention;
5+
import java.lang.annotation.RetentionPolicy;
6+
import java.lang.annotation.Target;
7+
8+
@Target(ElementType.METHOD)
9+
@Retention(RetentionPolicy.RUNTIME)
10+
public @interface StartNewTrace {
11+
String value() default "";
12+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package com.cleanengine.coin.common.annotation;
2+
3+
import io.opentelemetry.api.GlobalOpenTelemetry;
4+
import io.opentelemetry.api.trace.Span;
5+
import io.opentelemetry.api.trace.Tracer;
6+
import io.opentelemetry.context.Scope;
7+
import lombok.RequiredArgsConstructor;
8+
import org.aspectj.lang.ProceedingJoinPoint;
9+
import org.aspectj.lang.annotation.Around;
10+
import org.aspectj.lang.annotation.Aspect;
11+
import org.aspectj.lang.reflect.MethodSignature;
12+
import org.springframework.stereotype.Component;
13+
import java.lang.reflect.Method;
14+
15+
@Aspect
16+
@Component
17+
@RequiredArgsConstructor
18+
public class StartNewTraceAspect {
19+
20+
@Around("@annotation(com.cleanengine.coin.common.annotation.StartNewTrace)")
21+
public Object createNewTrace(ProceedingJoinPoint joinPoint) throws Throwable {
22+
Tracer tracer = GlobalOpenTelemetry.getTracer("com.cleanengine.coin");
23+
24+
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
25+
Method method = signature.getMethod();
26+
StartNewTrace newTraceAnnotation = method.getAnnotation(StartNewTrace.class);
27+
28+
String spanName = newTraceAnnotation.value().isEmpty() ?
29+
signature.getDeclaringType().getSimpleName() + "." + method.getName() :
30+
newTraceAnnotation.value();
31+
32+
Span span = tracer.spanBuilder(spanName).setNoParent().startSpan();
33+
34+
try (Scope scope = span.makeCurrent()) {
35+
return joinPoint.proceed();
36+
} catch (Exception e) {
37+
span.recordException(e);
38+
throw e;
39+
} finally {
40+
span.end();
41+
}
42+
}
43+
}
Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.cleanengine.coin.configuration;
22

33

4+
import org.springframework.beans.factory.annotation.Value;
45
import org.springframework.context.annotation.Configuration;
56
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
67
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
@@ -11,14 +12,8 @@
1112
@EnableWebSocketMessageBroker
1213
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
1314

14-
private static final String[] ALLOWED_ORIGINS = {
15-
"http://localhost:63342",
16-
"http://localhost:63343",
17-
"http://localhost:8080",
18-
"http://localhost:5500",
19-
"http://localhost:5173",
20-
"https://investfuture.my"
21-
};
15+
@Value("${spring.security.allowed-origins}")
16+
private String[] allowedOrigins;
2217

2318
@Override
2419
public void configureMessageBroker(MessageBrokerRegistry config) {
@@ -34,9 +29,7 @@ public void registerStompEndpoints(StompEndpointRegistry registry) {
3429

3530
private void registerEndpoint(StompEndpointRegistry registry, String endpoint) {
3631
registry.addEndpoint(endpoint)
37-
.setAllowedOrigins(ALLOWED_ORIGINS);
32+
.setAllowedOrigins(allowedOrigins);
3833
}
3934

40-
}
41-
42-
35+
}

src/main/java/com/cleanengine/coin/configuration/apiSwagger/SwaggerConfig.java

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,41 +3,26 @@
33
import org.springframework.context.annotation.Bean;
44
import org.springframework.context.annotation.Configuration;
55

6-
import io.swagger.v3.oas.models.Components;
76
import io.swagger.v3.oas.models.OpenAPI;
87
import io.swagger.v3.oas.models.info.Info;
9-
import io.swagger.v3.oas.models.security.SecurityRequirement;
10-
import io.swagger.v3.oas.models.security.SecurityScheme;
118
import io.swagger.v3.oas.models.servers.Server;
129

1310
@Configuration
1411
public class SwaggerConfig {
12+
1513
@Bean
1614
public OpenAPI openAPI() {
1715
// API 기본 정보 설정
1816
Info info = new Info()
19-
.title("investFuture API Document")
17+
.title("InvestFuture API Document")
2018
.version("1.0")
21-
.description(
22-
"환영합니다.\n")
19+
.description("Private API 호출 시 Cookie에 직접 설정해주세요!\n")
2320
.contact(new io.swagger.v3.oas.models.info.Contact().email("[email protected]"));
2421

25-
// JWT 인증 방식 설정
26-
String jwtScheme = "jwtAuth";
27-
SecurityRequirement securityRequirement = new SecurityRequirement().addList(jwtScheme);
28-
Components components = new Components()
29-
.addSecuritySchemes(jwtScheme, new SecurityScheme()
30-
.name("Authorization")
31-
.type(SecurityScheme.Type.HTTP)
32-
.in(SecurityScheme.In.HEADER)
33-
.scheme("Bearer")
34-
.bearerFormat("JWT"));
35-
3622
// Swagger UI 설정 및 보안 추가
3723
return new OpenAPI()
3824
.addServersItem(new Server().url("http://localhost:8080")) // 추가적인 서버 URL 설정 가능
39-
.components(components)
40-
.info(info)
41-
.addSecurityItem(securityRequirement);
25+
.info(info);
4226
}
27+
4328
}

src/main/java/com/cleanengine/coin/orderbook/domain/OrderBook.java

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,38 +22,42 @@ public void updateOrderBookOnNewOrder(boolean isBuyOrder, Double price, Double o
2222
if(isBuyOrder){
2323
BuyOrderBookUnit buyOrderBookUnit = buyOrderBookUnitMap.get(price);
2424
if(buyOrderBookUnit == null){
25-
buyOrderBookUnit = new BuyOrderBookUnit(price, orderSize);
26-
buyOrderBookUnitMap.put(price, buyOrderBookUnit);
27-
buyOrderBookUnitListSet.add(buyOrderBookUnit);
25+
addBuyOrderBookUnit(price, orderSize);
2826
} else {
2927
buyOrderBookUnit.addOrder(orderSize);
3028
}
3129
} else {
3230
SellOrderBookUnit sellOrderBookUnit = sellOrderBookUnitMap.get(price);
3331
if(sellOrderBookUnit == null){
34-
sellOrderBookUnit = new SellOrderBookUnit(price, orderSize);
35-
sellOrderBookUnitMap.put(price, sellOrderBookUnit);
36-
sellOrderBookUnitListSet.add(sellOrderBookUnit);
32+
addSellOrderBookUnit(price, orderSize);
3733
} else {
3834
sellOrderBookUnit.addOrder(orderSize);
3935
}
4036
}
4137
}
4238

4339
public void updateOrderBookOnTradeExecuted(boolean isBuyOrder, Double price, Double orderSize) {
44-
if(isBuyOrder){
40+
if(approxEquals(orderSize, 0.0) || approxEquals(price, 0.0)){
41+
throw new IllegalArgumentException("orderSize or price cannot be 0.0");
42+
}
43+
44+
if(isBuyOrder) {
4545
BuyOrderBookUnit buyOrderBookUnit = buyOrderBookUnitMap.get(price);
46+
if(buyOrderBookUnit == null) {
47+
return;
48+
}
4649
buyOrderBookUnit.executeTrade(orderSize);
4750
if(approxEquals(buyOrderBookUnit.getSize(), 0.0)){
48-
buyOrderBookUnitMap.remove(price);
49-
buyOrderBookUnitListSet.remove(buyOrderBookUnit);
51+
removeBuyOrderBookUnit(buyOrderBookUnit, price);
5052
}
5153
} else {
5254
SellOrderBookUnit sellOrderBookUnit = sellOrderBookUnitMap.get(price);
55+
if(sellOrderBookUnit == null) {
56+
return;
57+
}
5358
sellOrderBookUnit.executeTrade(orderSize);
5459
if(approxEquals(sellOrderBookUnit.getSize(), 0.0)){
55-
sellOrderBookUnitMap.remove(price);
56-
sellOrderBookUnitListSet.remove(sellOrderBookUnit);
60+
removeSellOrderBookUnit(sellOrderBookUnit, price);
5761
}
5862
}
5963
}
@@ -71,4 +75,40 @@ public List<OrderBookUnit> getSellOrderBookList(int size){
7175
.limit(size)
7276
.collect(Collectors.toList());
7377
}
78+
79+
protected synchronized void addBuyOrderBookUnit(Double price, Double size) {
80+
BuyOrderBookUnit buyOrderBookUnit = buyOrderBookUnitMap.get(price);
81+
if(buyOrderBookUnit != null){
82+
return;
83+
}
84+
85+
buyOrderBookUnit = new BuyOrderBookUnit(price, size);
86+
buyOrderBookUnitMap.put(price, buyOrderBookUnit);
87+
buyOrderBookUnitListSet.add(buyOrderBookUnit);
88+
}
89+
90+
protected synchronized void addSellOrderBookUnit(Double price, Double size) {
91+
SellOrderBookUnit sellOrderBookUnit = sellOrderBookUnitMap.get(price);
92+
if(sellOrderBookUnit != null){
93+
return;
94+
}
95+
96+
sellOrderBookUnit = new SellOrderBookUnit(price, size);
97+
sellOrderBookUnitMap.put(price, sellOrderBookUnit);
98+
sellOrderBookUnitListSet.add(sellOrderBookUnit);
99+
}
100+
101+
protected synchronized void removeBuyOrderBookUnit(BuyOrderBookUnit buyOrderBookUnit, Double price) {
102+
if(approxEquals(buyOrderBookUnit.getSize(), 0.0)) {
103+
buyOrderBookUnitMap.remove(price);
104+
buyOrderBookUnitListSet.remove(buyOrderBookUnit);
105+
}
106+
}
107+
108+
protected synchronized void removeSellOrderBookUnit(SellOrderBookUnit sellOrderBookUnit, Double price) {
109+
if(approxEquals(sellOrderBookUnit.getSize(), 0.0)) {
110+
sellOrderBookUnitMap.remove(price);
111+
sellOrderBookUnitListSet.remove(sellOrderBookUnit);
112+
}
113+
}
74114
}

0 commit comments

Comments
 (0)