프로젝트를 진행하던 도중 유저의 로그인 기록을 자세히 남기고싶었다. 접속한 디바이스, 그리고 OS가 무엇인지도 같이 저장하여, 어떤 종류의 디비이스를 사용하는 유저들이 많이 젒속하는지 파악하기 위해 User-Agent 문자열을 분석해 주는 라이브러리인 YAUAA를 사용해 보기로 했다.
YAUAA -> 공식문서 링크
라이브러리 설치
YAUAA를 사용하기 위해서는 라이브러리를 추가해 줘야 한다. 나는 yml을 사용하고 있기에 메이븐 리포지토리를 활용하여
implementation("nl.basjes.parse.useragent:yauaa:7.28.1")
의존성을 추가해 주었다.
config 생성
공식문서를 살펴보면 UserAgentAnalyzer 인스턴스를 생성해서 사용해야 하는데, 초기화 비용이 많이 든다고 한다. 그래서 나는 config 파일을 생성하여 스프링 빈으로 등록해 주기로 했다.
@Configuration
public class UserAgentConfig {
@Bean
public UserAgentAnalyzer userAgentAnalyzer() {
return UserAgentAnalyzer
.newBuilder()
.hideMatcherLoadStats()
.withCache(10000)
.withField("DeviceClass")
.withField("OperatingSystemName")
.withField("AgentName")
.build();
}
}
.hideMatcherLoadStats() 는 YAUAA가 초기화 될때 내부 로드 상태 정보를 로그에 남기지 않게 하는것이다.
.withCache(10000) 는 User-Agent 분석 결과를 캐시에 저장 하도록 설정하는 것인데 어차피 로그인 로직에서만 체크하고 따로 동일한 User-Agent에 대해 다시 분석할 일이 없을것 같아 메모리를 할당 하지 않기로 했다.
withField
withField를 활용하여 원하는 필드를 설정할 수 있다.
- ("DeviceClass") : 디바이스 (예 - 태블릿, 모바일, PC)
- ("OperatingSystemName") : OS (예 - window, iOS, Android)
- ("AgentName") : 브라우저 ( 예 - Chrom, safari
아래의 field name을 파스칼케이스로 활용하여 다양한 필드를 가져올 수 있다.
Service 구현
처음에는 Util 이름으로 클래스를 생성하였다가 스프링 빈을 등록해 주어야 하기에 Util이란 이름보다는 Service이름으로 생성하였다.
@Service
@RequiredArgsConstructor
public class UserAgentService {
private final UserAgentAnalyzer userAgentAnalyzer;
public String getDeviceClass(String userAgentString) {
UserAgent userAgent = userAgentAnalyzer.parse(userAgentString);
return userAgent.getValue("DeviceClass");
}
public String getOperatingSystem(String userAgentString) {
UserAgent userAgent = userAgentAnalyzer.parse(userAgentString);
return userAgent.getValue("OperatingSystemName");
}
public String getBrowser(String userAgentString) {
UserAgent userAgent = userAgentAnalyzer.parse(userAgentString);
return userAgent.getValue("AgentName");
}
public String isDevice(HttpServletRequest request){
String userAgentString = request.getHeader("User-Agent");
if (userAgentString == null || userAgentString.isEmpty()) {
return "알 수 없는 기기";
}
String deviceClass = getDeviceClass(userAgentString);
return deviceClass != null ? deviceClass : "알 수 없는 기기";
}
public String isOs(HttpServletRequest request){
String userAgentString = request.getHeader("User-Agent");
if (userAgentString == null || userAgentString.isEmpty()) {
return "알 수 없는 운영체제";
}
String osName = getOperatingSystem(userAgentString);
return osName != null ? osName : "알 수 없는 운영체제";
}
public String isBrowser(HttpServletRequest request){
String userAgentString = request.getHeader("User-Agent");
if (userAgentString == null || userAgentString.isEmpty()) {
return "알 수 없는 브라우저";
}
String browserName = getBrowser(userAgentString);
return browserName != null ? browserName : "알 수 없는 브라우저";
}
}
OS 버전 오류
OS의 버전도 같이 가져오고 싶어 시도해 보았으나 버전이 잘 나오지 않는 버그를 발견했다.
공식문서를 살펴보니 브라우저들의 정책으로 자세한 정보가 나오지 않을 수 있다고 한다.