absl::LogSeverity — 로그 레벨 타입
한 줄 요약:
absl::LogSeverity는 4단계 로그 심각도를 표현하는 enum이고, 로깅 시스템의 다른 모든 부분이 이 type 위에 서 있다.NormalizeLogSeverity는 외부 시스템의 정수 코드를 안전하게 변환한다.
#어떤 문제를 푸는가
로그 심각도는 “어디서나 같은 것”처럼 보이지만 실제로는 라이브러리·시스템마다 다르다. syslog는 0~7의 8단계, log4j는 6단계, Python logging은 5단계. Abseil은 가장 단순한 4단계로 정한다.
namespace absl {enum class LogSeverity : int { kInfo = 0, kWarning = 1, kError = 2, kFatal = 3,};}왜 4단계인가. Google의 경험상 더 많은 단계는 일관되게 쓰이지 않는다. DEBUG 같은 추가 단계는 VLOG라는 별도 메커니즘으로 분리된다.
#4단계의 의미
| 단계 | 의미 | 처리 |
|---|---|---|
kInfo | 일상적인 정보 | 기록만, 알람 없음 |
kWarning | 잠재적 문제 | 기록, 일부 시스템에서 알람 |
kError | 명확한 실패 | 기록, 알람, 메트릭 |
kFatal | 회복 불가 | 기록 후 abort() |
kFatal이 특별하다. 로그를 남긴 직후 프로세스를 종료한다. LOG(FATAL) 이후의 코드는 실행되지 않는다.
LOG(INFO) << "Server started on port " << port;LOG(WARNING) << "Retry attempt " << n;LOG(ERROR) << "Failed to connect: " << s;LOG(FATAL) << "Invariant violated"; // 이 후로 코드 실행 안 됨#API
#enum과 utility 함수
#include "absl/base/log_severity.h"
absl::LogSeverity s = absl::LogSeverity::kError;
// 이름 얻기const char* name = absl::LogSeverityName(s); // "ERROR"
// 외부 정수를 안전하게 변환int external_code = 2;absl::LogSeverity normalized = absl::NormalizeLogSeverity(external_code);// out-of-range는 가장 가까운 valid 값으로 clamp#LogSeverityAtLeast
특정 임계값 이상의 심각도만 통과시키는 enum.
enum class LogSeverityAtLeast : int { kInfo = static_cast<int>(LogSeverity::kInfo), kWarning = static_cast<int>(LogSeverity::kWarning), kError = static_cast<int>(LogSeverity::kError), kFatal = static_cast<int>(LogSeverity::kFatal), kInfinity = 1000,};kInfinity가 추가되어 있어 “어떤 로그도 통과시키지 않음”을 표현할 수 있다.
// FLAGS_minloglevel 같은 설정absl::SetMinLogLevel(absl::LogSeverityAtLeast::kWarning);// 이제 INFO 로그는 무시됨#LogSeverityAtMost
반대 방향.
enum class LogSeverityAtMost : int { kNegativeInfinity = -1000, kInfo = static_cast<int>(LogSeverity::kInfo), kWarning = static_cast<int>(LogSeverity::kWarning), kError = static_cast<int>(LogSeverity::kError), kFatal = static_cast<int>(LogSeverity::kFatal),};특정 임계값 이하만 처리. testing에서 유용. “FATAL은 죽이지 말고 WARNING으로 다뤄라” 같은 패턴.
#NormalizeLogSeverity의 역할
외부 시스템과 통합할 때 정수 값을 받게 된다.
// 외부 protobuf에서 받은 enum 정수int proto_severity = proto.log_severity(); // 0, 1, 2, 3 또는 invalid
// 직접 cast하면 위험absl::LogSeverity bad = static_cast<absl::LogSeverity>(proto_severity);// proto_severity가 99라면? — UB 가능성
// Goodabsl::LogSeverity good = absl::NormalizeLogSeverity(proto_severity);// 0~3 범위 밖이면 kInfo(아래) 또는 kFatal(위)로 clamp구현은 단순하다.
// 의사 코드constexpr LogSeverity NormalizeLogSeverity(int s) { if (s < static_cast<int>(LogSeverity::kInfo)) return LogSeverity::kInfo; if (s > static_cast<int>(LogSeverity::kFatal)) return LogSeverity::kFatal; return static_cast<LogSeverity>(s);}오버로드도 있다.
constexpr LogSeverity NormalizeLogSeverity(LogSeverity s); // identityconstexpr LogSeverity NormalizeLogSeverity(int s); // clamp#왜 LogSeverity::kInfo인가 — naming
Abseil은 enum class를 쓰면서 멤버 이름에 k 접두사를 붙인다. Google C++ Style Guide의 enum 멤버 명명 규칙.
// Abseil 스타일enum class LogSeverity { kInfo, kWarning, kError, kFatal,};
// 다른 라이브러리에서 흔히 보는 스타일enum class Severity { INFO, WARNING, ERROR, FATAL,};대문자 매크로(INFO, ERROR)와의 충돌을 피하기 위해서다. Windows.h가 ERROR를 매크로로 정의해 두기 때문에 그냥 Severity::ERROR는 일부 환경에서 깨진다. k 접두사가 이 충돌을 우회한다.
호환을 위해 별칭이 제공된다.
// LogSeverity::kInfo도 가능, INFO 매크로 호환도 LOG(INFO)에서 처리LOG(INFO) << "..."; // 내부적으로 absl::LogSeverity::kInfo로 변환#외부 시스템과의 매핑
대표적인 매핑 예시.
#syslog와의 매핑
int ToSyslog(absl::LogSeverity s) { switch (s) { case absl::LogSeverity::kInfo: return 6; // LOG_INFO case absl::LogSeverity::kWarning: return 4; // LOG_WARNING case absl::LogSeverity::kError: return 3; // LOG_ERR case absl::LogSeverity::kFatal: return 2; // LOG_CRIT }}#glog와의 매핑 (호환)
Abseil 로깅이 glog의 후속이므로 glog 사용자는 거의 그대로 마이그레이션 가능하다.
// gloggoogle::INFO // == 0google::WARNING // == 1google::ERROR // == 2google::FATAL // == 3
// Abseil — 같은 정수 값absl::LogSeverity::kInfo // 0absl::LogSeverity::kWarning // 1absl::LogSeverity::kError // 2absl::LogSeverity::kFatal // 3#Python logging과의 매핑
int ToPython(absl::LogSeverity s) { switch (s) { case absl::LogSeverity::kInfo: return 20; // INFO case absl::LogSeverity::kWarning: return 30; // WARNING case absl::LogSeverity::kError: return 40; // ERROR case absl::LogSeverity::kFatal: return 50; // CRITICAL }}DEBUG(10) 단계는 별도로 처리한다. Abseil은 VLOG(level)로 매핑한다.
#코드 리뷰 포인트
// 회피 — 외부 정수를 직접 castauto s = static_cast<absl::LogSeverity>(user_input);
// Good — Normalizeauto s = absl::NormalizeLogSeverity(user_input);// 회피 — LogSeverity를 int로 비교if (static_cast<int>(severity) >= 2) { // 매직 넘버. 의도 불명확.}
// Goodif (severity >= absl::LogSeverity::kError) { // enum class의 operator>= 사용}// 회피 — switch에 default를 두고 새 case 추가를 잊는 코드switch (s) { case absl::LogSeverity::kInfo: return Handle(s); default: return HandleDefault();}// LogSeverity가 5단계가 되면? — default가 silent하게 잡아먹음
// Good — 모든 case 명시, default 없음switch (s) { case absl::LogSeverity::kInfo: return HandleInfo(); case absl::LogSeverity::kWarning: return HandleWarning(); case absl::LogSeverity::kError: return HandleError(); case absl::LogSeverity::kFatal: return HandleFatal();}// 컴파일러가 -Wswitch로 누락된 case 경고#자주 보는 안티패턴
// 회피 — LOG(FATAL) 이후의 코드LOG(FATAL) << "Bad state";DoCleanup(); // 실행 안 됨return 0; // 도달 불가능
// Good — FATAL이 abort한다는 걸 명시LOG(FATAL) << "Bad state"; // [[noreturn]] 효과// 함수 끝// 회피 — LOG(FATAL)을 control flow에 의존if (something_bad) { LOG(FATAL) << "...";} else { DoNormal();}return Result();// FATAL은 unrecoverable. 정상 종료 경로에 두지 말 것.// CHECK 매크로가 더 적합할 때가 많다.// 회피 — LogSeverity를 enum이 아니라 string으로std::string severity = "ERROR";if (severity == "ERROR") { ... }// 오타에 취약. enum class를 쓰자.#정리
absl::LogSeverity는 4단계 enum class. INFO/WARNING/ERROR/FATAL.kFatal은 abort를 동반. 그 뒤의 코드는 실행되지 않음.- 외부 정수는
NormalizeLogSeverity로 clamp. - enum 멤버에
k접두사. Windows.h의ERROR매크로 충돌 회피. - glog와 ABI 호환되는 정수 값.
#다음 편
Part 2-04에서 Abseil의 type_traits를 본다. C++17에서 표준화된 negation, conjunction, void_t 같은 utility를 C++14에서도 쓰기 위한 polyfill이 무엇이고, 어떻게 구현되어 있는지.
#관련 항목
Abseil Code Review · 9 of 79
- 1 Abseil Code Review — Google production-grade C++ 라이브러리 분석
- 2 Abseil 개요 — Google이 std를 보완한 이유
- 3 Abseil 설계 철학 — std 호환과 추가 기능의 균형
- 4 Abseil 빌드와 의존성 — Bazel vs CMake
- 5 Abseil LTS vs HEAD 릴리스 모델 분석
- 6 Abseil Versioning과 ABI 호환성 정책
- 7 Abseil 매크로 — ABSL_HAVE_*·ABSL_ATTRIBUTE_*
- 8 Abseil ABSL_PREDICT_TRUE/FALSE — branch hint
- 9 absl::LogSeverity — 로그 레벨 타입
- 10 Abseil type_traits — negation·conjunction·void_t
- 11 Abseil Conformance·Policy 분석
- 12 Abseil Memory utilities 분석
- 13 Abseil raw_logging — heap-free 로깅
- 14 Abseil thread_annotations — clang TSA 통합
- 15 absl::Status — exception-free error handling
- 16 absl::StatusOr<T> — 값 또는 에러
- 17 absl status_macros — ASSIGN_OR_RETURN·RETURN_IF_ERROR
- 18 absl::Status payload — 구조화된 에러 컨텍스트
- 19 absl::Status ↔ exception 변환 패턴
- 20 absl::string_view — non-owning 문자열 참조
- 21 absl::string_view 함정 — dangling·c_str·임시 객체
- 22 absl::StrCat — 가변 인자 문자열 연결과 AlphaNum
- 23 absl::StrSplit — Delimiter·Predicate·컨테이너 변환
- 24 absl::StrJoin — 컨테이너 결합과 Formatter
- 25 absl::StrFormat — type-safe printf·FormatSpec
- 26 Abseil ASCII 함수 — locale-free 분류·대소문자 변환
- 27 Abseil Escape — CEscape·HexEscape·Base64
- 28 absl::flat_hash_map — Swiss Table 기반 hash map
- 29 absl::flat_hash_set — set 버전 Swiss Table
- 30 absl::node_hash_map — stable pointer가 필요할 때
- 31 absl::btree_map — sorted·cache-friendly B-tree
- 32 absl::FixedArray — 런타임 크기 stack 배열
- 33 absl::InlinedVector — small buffer optimization
- 34 Abseil Swiss Table internals — control byte·SIMD probing
- 35 absl::Mutex — reader-writer·fairness·deadlock 검출
- 36 absl::Mutex Conditional Critical Section — Await로 cv 없애기
- 37 absl::Notification — once-only signal
- 38 absl::BlockingCounter·Barrier — 다중 thread 조율
- 39 absl::Mutex annotations — clang thread-safety로 race를 컴파일 타임에
- 40 absl::Time·Duration 분석 — 단단한 type
- 41 absl::Time Format·Parse
- 42 absl::CivilTime 분석
- 43 absl::time_zone 분석
- 44 absl::Time mocking — 테스트 친화 시간
- 45 absl::BitGen — 모던 난수 생성기
- 46 Abseil Random Distributions — Uniform·Exponential
- 47 Abseil Mocking Random — 테스트 결정성
- 48 Abseil Random Seeding·Entropy
- 49 absl::int128·uint128 분석
- 50 absl::bits — popcount·countl_zero
- 51 absl::optional vs std::optional
- 52 absl::variant 분석
- 53 absl::span 분석
- 54 absl::any 분석
- 55 absl::compare — three-way 비교
- 56 Abseil utility — apply·in_place
- 57 Abseil AbslHashValue 분석
- 58 Abseil HashState chaining
- 59 Abseil Custom hashable 구현
- 60 Abseil LOG·VLOG·CHECK 분석
- 61 Abseil LogSink 분석
- 62 Abseil LogEntry·structured logging
- 63 Abseil Stack trace·failure_signal_handler
- 64 ABSL_FLAG 정의 분석
- 65 Abseil ParseCommandLine 동작
- 66 Abseil Flag introspection·validation
- 67 Google 스타일의 Abseil 사용 패턴
- 68 Abseil 자주 보는 anti-pattern
- 69 std → absl 마이그레이션 전략
- 70 absl::Cleanup — 함수 종료 시 실행 보장
- 71 Abseil algorithm container 확장 — c_sort·c_find_if·c_count_if
- 72 absl::function_ref와 any_invocable — 함수 객체 전달의 두 축
- 73 absl::bind_front와 Overload — 함수 객체 보조 도구
- 74 absl::Cord — 분산 시스템용 대용량 문자열
- 75 absl::from_chars·SimpleAtoi — 빠른 숫자 변환
- 76 absl::Cord vs std::string — 선택 기준과 메모리 프로파일
- 77 absl::GetStackTrace와 Symbolize — crash 시 readable stack
- 78 absl::ComputeCrc32c — 하드웨어 가속 체크섬
- 79 absl::PeriodicSampler — 적응형 샘플링·jitter 회피
관련 글
Abseil Stack trace·failure_signal_handler
absl::Symbolize, GetStackTrace, InstallFailureSignalHandler — crash 시점에 stack을 찍어 남기는 진단 인프라.
같은 시리즈에서 이어 읽기
Abseil LogEntry·structured logging
absl::LogEntry — 한 로그 항목의 메타데이터(severity, timestamp, source location, message). 구조화 로깅의 기반.
같은 시리즈에서 이어 읽기
Abseil LogSink 분석
absl::LogSink — 출력 destination 커스터마이징. 파일·syslog·원격 collector·테스트 캡처.
같은 시리즈에서 이어 읽기