Skip to content

Commit b331d3e

Browse files
authored
Merge pull request #173 from GTable/feature/#171-add-error-logging
Feat: Feign 활용한 디스코드 에러 시스템 구축
2 parents 290432e + c31771d commit b331d3e

16 files changed

Lines changed: 384 additions & 189 deletions

File tree

nowait-app-admin-api/build.gradle

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,16 @@ repositories {
1717
maven { url 'https://jitpack.io' }
1818
}
1919

20+
ext {
21+
set('springCloudVersion', "2025.0.0")
22+
}
23+
24+
dependencyManagement {
25+
imports {
26+
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
27+
}
28+
}
29+
2030
dependencies {
2131
implementation project(':nowait-common')
2232
implementation project(':nowait-infra')
@@ -49,13 +59,13 @@ dependencies {
4959
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
5060
runtimeOnly 'com.mysql:mysql-connector-j'
5161

52-
// 로그
53-
implementation 'org.springframework.boot:spring-boot-starter-aop'
54-
runtimeOnly 'org.fusesource.jansi:jansi:2.4.0'
55-
5662
// 디스코드 웹훅
5763
implementation 'com.github.napstr:logback-discord-appender:1.0.0'
5864

65+
//feign
66+
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
67+
implementation group: 'io.github.openfeign', name: 'feign-gson', version: '11.0'
68+
5969
// 기타 필요 라이브러리 (예: Lombok)
6070
compileOnly 'org.projectlombok:lombok'
6171
annotationProcessor 'org.projectlombok:lombok'

nowait-app-admin-api/src/main/java/com/nowait/ApiAdminApplication.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package com.nowait;
22

33
import org.springframework.boot.autoconfigure.SpringBootApplication;
4+
import org.springframework.cloud.openfeign.EnableFeignClients;
45
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
56
import org.springframework.scheduling.annotation.EnableScheduling;
67

78
@EnableJpaAuditing
89
@EnableScheduling
10+
@EnableFeignClients
911
@SpringBootApplication
1012
public class ApiAdminApplication {
1113
public static void main(String[] args) {
Lines changed: 92 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package com.nowait.applicationadmin.exception;
22

33
import static com.nowait.common.exception.ErrorMessage.*;
4+
import static org.springframework.http.HttpStatus.BAD_REQUEST;
5+
import static org.springframework.http.HttpStatus.FORBIDDEN;
6+
import static org.springframework.http.HttpStatus.NOT_FOUND;
47
import static org.springframework.http.HttpStatus.UNAUTHORIZED;
5-
import static org.springframework.http.HttpStatus.*;
68

79
import java.util.Map;
810
import java.util.stream.Collectors;
@@ -15,12 +17,14 @@
1517
import org.springframework.web.bind.annotation.ExceptionHandler;
1618
import org.springframework.web.bind.annotation.ResponseStatus;
1719
import org.springframework.web.bind.annotation.RestControllerAdvice;
20+
import org.springframework.web.context.request.WebRequest;
1821
import org.springframework.web.multipart.MultipartException;
1922

2023
import com.nowait.applicationadmin.security.exception.ResourceNotFoundException;
2124
import com.nowait.applicationadmin.security.exception.UnauthorizedException;
2225
import com.nowait.common.exception.ErrorMessage;
2326
import com.nowait.common.exception.ErrorResponse;
27+
import com.nowait.discord.service.DiscordAlarmService;
2428
import com.nowait.domaincorerdb.menu.exception.MenuCreationUnauthorizedException;
2529
import com.nowait.domaincorerdb.menu.exception.MenuDeleteUnauthorizedException;
2630
import com.nowait.domaincorerdb.menu.exception.MenuUpdateUnauthorizedException;
@@ -41,189 +45,224 @@
4145
import com.nowait.domaincorerdb.user.exception.UserNotFoundException;
4246

4347
import io.swagger.v3.oas.annotations.Hidden;
48+
import lombok.RequiredArgsConstructor;
4449
import lombok.extern.slf4j.Slf4j;
4550

4651
@Slf4j
4752
@Hidden
4853
@RestControllerAdvice
54+
@RequiredArgsConstructor
4955
public class GlobalExceptionHandler {
5056

51-
@ResponseStatus(value = BAD_REQUEST)
57+
private final DiscordAlarmService discordAlarmService;
58+
59+
// Discord 알림 헬퍼
60+
private void alarm(Exception e, WebRequest request) {
61+
discordAlarmService.sendDiscordAdminAlarm(e, request);
62+
}
63+
64+
@ResponseStatus(BAD_REQUEST)
5265
@ExceptionHandler(BusinessException.class)
53-
public ErrorResponse handleBusinessException(BusinessException e) {
66+
public ErrorResponse handleBusinessException(BusinessException e, WebRequest request) {
67+
alarm(e, request);
5468
log.error("handleBusinessException", e);
5569
return new ErrorResponse(e.getMessage(), e.getCode());
5670
}
5771

58-
@ResponseStatus(value = BAD_REQUEST)
72+
@ResponseStatus(BAD_REQUEST)
5973
@ExceptionHandler(MethodArgumentNotValidException.class)
60-
public ErrorResponse handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
74+
public ErrorResponse handleMethodArgumentNotValidException(MethodArgumentNotValidException e, WebRequest request) {
75+
alarm(e, request);
6176
log.error("handleMethodArgumentNotValidException", e);
6277
Map<String, String> errors = getErrors(e);
6378
return new ErrorResponse(INVALID_INPUT_VALUE.getMessage(), INVALID_INPUT_VALUE.getCode(), errors);
6479
}
6580

66-
@ResponseStatus(value = BAD_REQUEST)
81+
@ResponseStatus(BAD_REQUEST)
6782
@ExceptionHandler(HttpMessageNotReadableException.class)
68-
public ErrorResponse handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
83+
public ErrorResponse handleHttpMessageNotReadableException(HttpMessageNotReadableException e, WebRequest request) {
84+
alarm(e, request);
6985
log.error("handleHttpMessageNotReadableException", e);
7086
return new ErrorResponse(INVALID_INPUT_VALUE.getMessage(), INVALID_INPUT_VALUE.getCode());
7187
}
7288

73-
@ResponseStatus(value = BAD_REQUEST)
89+
@ResponseStatus(BAD_REQUEST)
7490
@ExceptionHandler(IllegalArgumentException.class)
75-
public ErrorResponse handleIllegalArgumentException(IllegalArgumentException e) {
91+
public ErrorResponse handleIllegalArgumentException(IllegalArgumentException e, WebRequest request) {
92+
alarm(e, request);
7693
log.error("handleIllegalArgumentException", e);
7794
return new ErrorResponse(e.getMessage(), INVALID_INPUT_VALUE.getCode());
7895
}
7996

80-
@ResponseStatus(value = BAD_REQUEST)
97+
@ResponseStatus(BAD_REQUEST)
8198
@ExceptionHandler(MissingRequestValueException.class)
82-
public ErrorResponse handleMissingRequestValueException(MissingRequestValueException e) {
99+
public ErrorResponse handleMissingRequestValueException(MissingRequestValueException e, WebRequest request) {
100+
alarm(e, request);
83101
log.error("handleMissingRequestValueExceptionException", e);
84102
return new ErrorResponse(INVALID_INPUT_VALUE.getMessage(), INVALID_INPUT_VALUE.getCode());
85103
}
86104

87-
@ResponseStatus(value = UNAUTHORIZED)
105+
@ResponseStatus(UNAUTHORIZED)
88106
@ExceptionHandler(UnauthorizedException.class)
89-
public ErrorResponse handleUnauthorizedException(UnauthorizedException e) {
90-
log.error("handleUnauthorizedExceptionException", e);
107+
public ErrorResponse handleUnauthorizedException(UnauthorizedException e, WebRequest request) {
108+
alarm(e, request);
109+
log.error("handleUnauthorizedException", e);
91110
return new ErrorResponse(e.getMessage(), e.getCode());
92111
}
93112

94-
@ResponseStatus(value = NOT_FOUND)
113+
@ResponseStatus(NOT_FOUND)
95114
@ExceptionHandler(ResourceNotFoundException.class)
96-
public ErrorResponse handleResourceNotFoundException(ResourceNotFoundException e) {
115+
public ErrorResponse handleResourceNotFoundException(ResourceNotFoundException e, WebRequest request) {
116+
alarm(e, request);
97117
log.error("handleResourceNotFoundExceptionException", e);
98118
return new ErrorResponse(e.getMessage(), e.getCode());
99119
}
100120

101-
@ResponseStatus(value = BAD_REQUEST)
121+
@ResponseStatus(BAD_REQUEST)
102122
@ExceptionHandler(MultipartException.class)
103-
public ErrorResponse handleMultipartException(MultipartException e) {
123+
public ErrorResponse handleMultipartException(MultipartException e, WebRequest request) {
124+
alarm(e, request);
104125
log.error("handleMultipartException", e);
105126
return new ErrorResponse(e.getMessage(), INVALID_INPUT_VALUE.getCode());
106127
}
107128

108-
@ResponseStatus(value = NOT_FOUND)
129+
@ResponseStatus(NOT_FOUND)
109130
@ExceptionHandler(UserNotFoundException.class)
110-
public ErrorResponse userNotFoundException(UserNotFoundException e) {
131+
public ErrorResponse userNotFoundException(UserNotFoundException e, WebRequest request) {
132+
alarm(e, request);
111133
log.error("userNotFoundException", e);
112134
return new ErrorResponse(e.getMessage(), NOTFOUND_USER.getCode());
113135
}
114136

115-
@ResponseStatus(value = BAD_REQUEST)
137+
@ResponseStatus(BAD_REQUEST)
116138
@ExceptionHandler(OrderParameterEmptyException.class)
117-
public ErrorResponse orderParameterEmptyException(OrderParameterEmptyException e) {
139+
public ErrorResponse orderParameterEmptyException(OrderParameterEmptyException e, WebRequest request) {
140+
alarm(e, request);
118141
log.error("orderParameterEmptyException", e);
119142
return new ErrorResponse(e.getMessage(), ORDER_PARAMETER_EMPTY.getCode());
120143
}
121144

122-
@ResponseStatus(value = BAD_REQUEST)
145+
@ResponseStatus(BAD_REQUEST)
123146
@ExceptionHandler(OrderItemsEmptyException.class)
124-
public ErrorResponse orderItemsEmptyException(OrderItemsEmptyException e) {
147+
public ErrorResponse orderItemsEmptyException(OrderItemsEmptyException e, WebRequest request) {
148+
alarm(e, request);
125149
log.error("orderItemsEmptyException", e);
126150
return new ErrorResponse(e.getMessage(), ORDER_ITEMS_EMPTY.getCode());
127151
}
128152

129-
@ResponseStatus(value = BAD_REQUEST)
153+
@ResponseStatus(BAD_REQUEST)
130154
@ExceptionHandler(DuplicateOrderException.class)
131-
public ErrorResponse duplicateOrderException(DuplicateOrderException e) {
155+
public ErrorResponse duplicateOrderException(DuplicateOrderException e, WebRequest request) {
156+
alarm(e, request);
132157
log.error("duplicateOrderException", e);
133158
return new ErrorResponse(e.getMessage(), ErrorMessage.DUPLICATE_ORDER.getCode());
134159
}
135160

136-
@ResponseStatus(value = FORBIDDEN)
161+
@ResponseStatus(FORBIDDEN)
137162
@ExceptionHandler(OrderViewUnauthorizedException.class)
138-
public ErrorResponse orderViewUnauthorizedException(OrderViewUnauthorizedException e) {
163+
public ErrorResponse orderViewUnauthorizedException(OrderViewUnauthorizedException e, WebRequest request) {
164+
alarm(e, request);
139165
log.error("orderViewUnauthorizedException", e);
140166
return new ErrorResponse(e.getMessage(), ORDER_VIEW_UNAUTHORIZED.getCode());
141167
}
142168

143-
@ResponseStatus(value = NOT_FOUND)
169+
@ResponseStatus(NOT_FOUND)
144170
@ExceptionHandler(OrderNotFoundException.class)
145-
public ErrorResponse orderNotFoundException(OrderNotFoundException e) {
171+
public ErrorResponse orderNotFoundException(OrderNotFoundException e, WebRequest request) {
172+
alarm(e, request);
146173
log.error("orderNotFoundException", e);
147174
return new ErrorResponse(e.getMessage(), ORDER_NOT_FOUND.getCode());
148175
}
149176

150-
@ResponseStatus(value = FORBIDDEN)
177+
@ResponseStatus(FORBIDDEN)
151178
@ExceptionHandler(OrderUpdateUnauthorizedException.class)
152-
public ErrorResponse orderUpdateUnauthorizedException(OrderUpdateUnauthorizedException e) {
179+
public ErrorResponse orderUpdateUnauthorizedException(OrderUpdateUnauthorizedException e, WebRequest request) {
180+
alarm(e, request);
153181
log.error("orderUpdateUnauthorizedException", e);
154182
return new ErrorResponse(e.getMessage(), ORDER_UPDATE_UNAUTHORIZED.getCode());
155183
}
156184

157-
@ResponseStatus(value = NOT_FOUND)
185+
@ResponseStatus(NOT_FOUND)
158186
@ExceptionHandler(ReservationNotFoundException.class)
159-
public ErrorResponse reservationNotFoundException(ReservationNotFoundException e) {
187+
public ErrorResponse reservationNotFoundException(ReservationNotFoundException e, WebRequest request) {
188+
alarm(e, request);
160189
log.error("reservationNotFoundException", e);
161190
return new ErrorResponse(e.getMessage(), NOTFOUND_RESERVATION.getCode());
162191
}
163192

164-
@ResponseStatus(value = FORBIDDEN)
193+
@ResponseStatus(FORBIDDEN)
165194
@ExceptionHandler(ReservationViewUnauthorizedException.class)
166-
public ErrorResponse reservationViewUnauthorizedException(ReservationViewUnauthorizedException e) {
167-
log.error("reservationViewUnauthorizedException", e);
195+
public ErrorResponse reservationViewUnauthorizedException(ReservationViewUnauthorizedException e, WebRequest request) {
196+
alarm(e, request);
197+
log.error("reservation_viewUnauthorizedException", e);
168198
return new ErrorResponse(e.getMessage(), RESERVATION_VIEW_UNAUTHORIZED.getCode());
169199
}
170200

171-
@ResponseStatus(value = FORBIDDEN)
201+
@ResponseStatus(FORBIDDEN)
172202
@ExceptionHandler(ReservationUpdateUnauthorizedException.class)
173-
public ErrorResponse reservationUpdateUnauthorizedException(ReservationUpdateUnauthorizedException e) {
203+
public ErrorResponse reservationUpdateUnauthorizedException(ReservationUpdateUnauthorizedException e, WebRequest request) {
204+
alarm(e, request);
174205
log.error("reservationUpdateUnauthorizedException", e);
175206
return new ErrorResponse(e.getMessage(), RESERVATION_UPDATE_UNAUTHORIZED.getCode());
176207
}
177208

178-
@ResponseStatus(value = FORBIDDEN)
209+
@ResponseStatus(FORBIDDEN)
179210
@ExceptionHandler(MenuCreationUnauthorizedException.class)
180-
public ErrorResponse menuCreationUnauthorizedException(MenuCreationUnauthorizedException e) {
211+
public ErrorResponse menuCreationUnauthorizedException(MenuCreationUnauthorizedException e, WebRequest request) {
212+
alarm(e, request);
181213
log.error("menuCreationUnauthorizedException", e);
182214
return new ErrorResponse(e.getMessage(), MENU_CREATION_UNAUTHORIZED.getCode());
183215
}
184216

185-
@ResponseStatus(value = FORBIDDEN)
217+
@ResponseStatus(FORBIDDEN)
186218
@ExceptionHandler(MenuViewUnauthorizedException.class)
187-
public ErrorResponse menuViewUnauthorizedException(MenuViewUnauthorizedException e) {
219+
public ErrorResponse menuViewUnauthorizedException(MenuViewUnauthorizedException e, WebRequest request) {
220+
alarm(e, request);
188221
log.error("menuViewUnauthorizedException", e);
189222
return new ErrorResponse(e.getMessage(), MENU_VIEW_UNAUTHORIZED.getCode());
190223
}
191224

192-
@ResponseStatus(value = FORBIDDEN)
225+
@ResponseStatus(FORBIDDEN)
193226
@ExceptionHandler(MenuUpdateUnauthorizedException.class)
194-
public ErrorResponse menuUpdateUnauthorizedException(MenuUpdateUnauthorizedException e) {
227+
public ErrorResponse menuUpdateUnauthorizedException(MenuUpdateUnauthorizedException e, WebRequest request) {
228+
alarm(e, request);
195229
log.error("menuUpdateUnauthorizedException", e);
196230
return new ErrorResponse(e.getMessage(), MENU_UPDATE_UNAUTHORIZED.getCode());
197231
}
198232

199-
@ResponseStatus(value = FORBIDDEN)
233+
@ResponseStatus(FORBIDDEN)
200234
@ExceptionHandler(MenuDeleteUnauthorizedException.class)
201-
public ErrorResponse menuDeleteUnauthorizedException(MenuDeleteUnauthorizedException e) {
235+
public ErrorResponse menuDeleteUnauthorizedException(MenuDeleteUnauthorizedException e, WebRequest request) {
236+
alarm(e, request);
202237
log.error("menuDeleteUnauthorizedException", e);
203238
return new ErrorResponse(e.getMessage(), MENU_DELETE_UNAUTHORIZED.getCode());
204239
}
205240

206-
@ResponseStatus(value = FORBIDDEN)
241+
@ResponseStatus(FORBIDDEN)
207242
@ExceptionHandler(StoreViewUnauthorizedException.class)
208-
public ErrorResponse storeViewUnauthorizedException(StoreViewUnauthorizedException e) {
243+
public ErrorResponse storeViewUnauthorizedException(StoreViewUnauthorizedException e, WebRequest request) {
244+
alarm(e, request);
209245
log.error("storeViewUnauthorizedException", e);
210246
return new ErrorResponse(e.getMessage(), STORE_VIEW_UNAUTHORIZED.getCode());
211247
}
212248

213-
@ResponseStatus(value = FORBIDDEN)
249+
@ResponseStatus(FORBIDDEN)
214250
@ExceptionHandler(StoreUpdateUnauthorizedException.class)
215-
public ErrorResponse storeUpdateUnauthorizedException(StoreUpdateUnauthorizedException e) {
251+
public ErrorResponse storeUpdateUnauthorizedException(StoreUpdateUnauthorizedException e, WebRequest request) {
252+
alarm(e, request);
216253
log.error("storeUpdateUnauthorizedException", e);
217254
return new ErrorResponse(e.getMessage(), STORE_UPDATE_UNAUTHORIZED.getCode());
218255
}
219256

220-
@ResponseStatus(value = FORBIDDEN)
257+
@ResponseStatus(FORBIDDEN)
221258
@ExceptionHandler(StoreDeleteUnauthorizedException.class)
222-
public ErrorResponse storeDeleteUnauthorizedException(StoreDeleteUnauthorizedException e) {
259+
public ErrorResponse storeDeleteUnauthorizedException(StoreDeleteUnauthorizedException e, WebRequest request) {
260+
alarm(e, request);
223261
log.error("storeDeleteUnauthorizedException", e);
224262
return new ErrorResponse(e.getMessage(), STORE_DELETE_UNAUTHORIZED.getCode());
225263
}
226264

265+
// 공통 에러 Map 생성
227266
private static Map<String, String> getErrors(MethodArgumentNotValidException e) {
228267
return e.getBindingResult()
229268
.getAllErrors()
@@ -235,5 +274,4 @@ private static Map<String, String> getErrors(MethodArgumentNotValidException e)
235274
(msg1, msg2) -> msg1 + ";" + msg2
236275
));
237276
}
238-
239277
}

nowait-app-admin-api/src/main/resources/logback-admin-dev.xml

Lines changed: 0 additions & 38 deletions
This file was deleted.

0 commit comments

Comments
 (0)