본문으로 건너뛰기
Abseil Code Review · 65/79

Abseil Flag introspection·validation

· Hawk · 2분 읽기

#검증 — Validator

flag 값이 합법한 범위인지 자동 검증.

#include "absl/flags/flag.h"
ABSL_FLAG(int32_t, port, 8080, "HTTP port");
static const auto port_validator = []() {
int32_t p = absl::GetFlag(FLAGS_port);
if (p <= 0 || p > 65535) {
LOG(FATAL) << "invalid --port: " << p;
}
return true;
}();

또는 더 형식적인 AbslParseFlag 단계에서 검증(아래).

#Custom type — AbslParseFlag / AbslUnparseFlag

내장 타입 외에는 두 함수를 정의해 flag 시스템에 등록.

struct LogLevel {
enum Value { kDebug, kInfo, kWarn, kError } value;
};
bool AbslParseFlag(absl::string_view text, LogLevel* out, std::string* error) {
if (text == "debug") { out->value = LogLevel::kDebug; return true; }
if (text == "info") { out->value = LogLevel::kInfo; return true; }
if (text == "warn") { out->value = LogLevel::kWarn; return true; }
if (text == "error") { out->value = LogLevel::kError; return true; }
*error = absl::StrCat("expected debug/info/warn/error, got ", text);
return false;
}
std::string AbslUnparseFlag(LogLevel level) {
switch (level.value) {
case LogLevel::kDebug: return "debug";
case LogLevel::kInfo: return "info";
case LogLevel::kWarn: return "warn";
case LogLevel::kError: return "error";
}
return "?";
}
ABSL_FLAG(LogLevel, log_level, LogLevel{LogLevel::kInfo}, "logging level");

Parse유효성 검증을 포함 — 잘못된 값이면 false 반환하고 error에 메시지. ParseCommandLine이 이 에러를 표시한다.

Terminal window
$ ./app --log_level=trace
ERROR: --log_level=trace: expected debug/info/warn/error, got trace

#Enum flag — 흔한 패턴

enum class Verbosity { kQuiet, kNormal, kVerbose, kDebug };
bool AbslParseFlag(absl::string_view text, Verbosity* v, std::string* err) {
static const auto kMap = absl::flat_hash_map<absl::string_view, Verbosity>{
{"quiet", Verbosity::kQuiet},
{"normal", Verbosity::kNormal},
{"verbose", Verbosity::kVerbose},
{"debug", Verbosity::kDebug},
};
auto it = kMap.find(text);
if (it == kMap.end()) {
*err = absl::StrCat("unknown verbosity: ", text);
return false;
}
*v = it->second;
return true;
}
std::string AbslUnparseFlag(Verbosity v) {
switch (v) {
case Verbosity::kQuiet: return "quiet";
case Verbosity::kNormal: return "normal";
case Verbosity::kVerbose: return "verbose";
case Verbosity::kDebug: return "debug";
}
return "?";
}
ABSL_FLAG(Verbosity, verbosity, Verbosity::kNormal, "logging verbosity");

int flag보다 이름이 명령행에 노출 되어 readability가 좋다.

#Range validation — Parse 안에서

struct PortNumber {
uint16_t value;
};
bool AbslParseFlag(absl::string_view text, PortNumber* p, std::string* err) {
int n;
if (!absl::SimpleAtoi(text, &n)) {
*err = absl::StrCat("not a number: ", text);
return false;
}
if (n <= 0 || n > 65535) {
*err = absl::StrCat("out of range [1, 65535]: ", n);
return false;
}
p->value = static_cast<uint16_t>(n);
return true;
}
std::string AbslUnparseFlag(PortNumber p) { return absl::StrCat(p.value); }
ABSL_FLAG(PortNumber, port, PortNumber{8080}, "HTTP port");

absl::SimpleAtoi로 안전 파싱. 잘못된 값이면 false로 거부.

#ReflectionFlag / introspection

런타임에 flag 메타데이터를 조회.

#include "absl/flags/reflection.h"
const absl::CommandLineFlag* f = absl::FindCommandLineFlag("port");
if (f) {
LOG(INFO) << "name: " << f->Name();
LOG(INFO) << "help: " << f->Help();
LOG(INFO) << "type: " << f->Typename();
LOG(INFO) << "current: " << f->CurrentValue();
LOG(INFO) << "default: " << f->DefaultValue();
}

모든 flag 순회:

absl::flags_internal::ForEachFlag([](absl::CommandLineFlag& f) {
LOG(INFO) << f.Name() << " = " << f.CurrentValue();
});

debug endpoint(/_/flags)로 노출하면 운영 중 현재 설정 확인 가능.

#SetFlag — 런타임 변경

absl::SetFlag(&FLAGS_port, 9090); // 타입 안전
// 이름(문자열)으로 설정하려면 reflection API를 거친다
std::string err;
absl::FindCommandLineFlag("port")->ParseFrom("9090", &err);

두 경로 모두 thread-safe. 다만 이미 캡처된 값은 안 바뀐다.

const bool verbose = absl::GetFlag(FLAGS_verbose); // 캡처
absl::SetFlag(&FLAGS_verbose, true);
if (verbose) { ... } // 여전히 이전 값

런타임 변경을 감지하려면 매번 GetFlag 호출(atomic load — 가볍지만 hot path는 회피).

#Admin endpoint 예 — HTTP로 flag 변경

void HandleSetFlag(absl::string_view name, absl::string_view value) {
auto* f = absl::FindCommandLineFlag(std::string(name));
if (!f) {
Respond(404, "no such flag");
return;
}
std::string err;
if (!f->ParseFrom(value, &err)) {
Respond(400, absl::StrCat("invalid value: ", err));
return;
}
LOG(INFO) << "flag changed: " << name << " = " << value;
Respond(200, "ok");
}

운영 중 디버그·실험 토글에 활용. prod 전용 권한 필수.

#회피 패턴

// 회피 — custom type validation 누락
bool AbslParseFlag(absl::string_view text, MyType* m, std::string* err) {
m->value = ParseSomething(text); // ❌ 항상 true 반환
return true;
}
// Good — 검증
bool AbslParseFlag(absl::string_view text, MyType* m, std::string* err) {
if (!Validate(text, err)) return false;
m->value = ParseSomething(text);
return true;
}
// 회피 — int flag로 enum 표현
ABSL_FLAG(int, log_level, 2, "0=debug, 1=info, 2=warn, 3=error"); // ❌ 의미 모호
// Good — enum + custom parser
ABSL_FLAG(LogLevel, log_level, LogLevel::kWarn, "...");
// 회피 — 런타임 변경에 의존하면서 캡처
int worker_count = absl::GetFlag(FLAGS_workers);
StartPool(worker_count);
// 이후 SetFlag(workers, ...) 해도 풀 크기 안 바뀜

#정리

  • 내장 타입 외 — AbslParseFlag/AbslUnparseFlag 한 쌍으로 custom 등록.
  • Parse 안에서 검증 + 변환 모두. 잘못된 값은 false + err.
  • enum flag는 이름이 CLI에 노출 — int magic number 회피.
  • absl::FindCommandLineFlag + ForEachFlag로 런타임 introspection.
  • SetFlag/SetFlagByName으로 동적 변경. 캡처된 값은 안 바뀌므로 hot path 주의.

#다음 장 예고

Part 13-01: Google 스타일의 Abseil 사용 패턴 — 코드 리뷰 정리.

#관련 항목

Abseil Code Review · 66 of 79

  1. 1 Abseil Code Review — Google production-grade C++ 라이브러리 분석
  2. 2 Abseil 개요 — Google이 std를 보완한 이유
  3. 3 Abseil 설계 철학 — std 호환과 추가 기능의 균형
  4. 4 Abseil 빌드와 의존성 — Bazel vs CMake
  5. 5 Abseil LTS vs HEAD 릴리스 모델 분석
  6. 6 Abseil Versioning과 ABI 호환성 정책
  7. 7 Abseil 매크로 — ABSL_HAVE_*·ABSL_ATTRIBUTE_*
  8. 8 Abseil ABSL_PREDICT_TRUE/FALSE — branch hint
  9. 9 absl::LogSeverity — 로그 레벨 타입
  10. 10 Abseil type_traits — negation·conjunction·void_t
  11. 11 Abseil Conformance·Policy 분석
  12. 12 Abseil Memory utilities 분석
  13. 13 Abseil raw_logging — heap-free 로깅
  14. 14 Abseil thread_annotations — clang TSA 통합
  15. 15 absl::Status — exception-free error handling
  16. 16 absl::StatusOr<T> — 값 또는 에러
  17. 17 absl status_macros — ASSIGN_OR_RETURN·RETURN_IF_ERROR
  18. 18 absl::Status payload — 구조화된 에러 컨텍스트
  19. 19 absl::Status ↔ exception 변환 패턴
  20. 20 absl::string_view — non-owning 문자열 참조
  21. 21 absl::string_view 함정 — dangling·c_str·임시 객체
  22. 22 absl::StrCat — 가변 인자 문자열 연결과 AlphaNum
  23. 23 absl::StrSplit — Delimiter·Predicate·컨테이너 변환
  24. 24 absl::StrJoin — 컨테이너 결합과 Formatter
  25. 25 absl::StrFormat — type-safe printf·FormatSpec
  26. 26 Abseil ASCII 함수 — locale-free 분류·대소문자 변환
  27. 27 Abseil Escape — CEscape·HexEscape·Base64
  28. 28 absl::flat_hash_map — Swiss Table 기반 hash map
  29. 29 absl::flat_hash_set — set 버전 Swiss Table
  30. 30 absl::node_hash_map — stable pointer가 필요할 때
  31. 31 absl::btree_map — sorted·cache-friendly B-tree
  32. 32 absl::FixedArray — 런타임 크기 stack 배열
  33. 33 absl::InlinedVector — small buffer optimization
  34. 34 Abseil Swiss Table internals — control byte·SIMD probing
  35. 35 absl::Mutex — reader-writer·fairness·deadlock 검출
  36. 36 absl::Mutex Conditional Critical Section — Await로 cv 없애기
  37. 37 absl::Notification — once-only signal
  38. 38 absl::BlockingCounter·Barrier — 다중 thread 조율
  39. 39 absl::Mutex annotations — clang thread-safety로 race를 컴파일 타임에
  40. 40 absl::Time·Duration 분석 — 단단한 type
  41. 41 absl::Time Format·Parse
  42. 42 absl::CivilTime 분석
  43. 43 absl::time_zone 분석
  44. 44 absl::Time mocking — 테스트 친화 시간
  45. 45 absl::BitGen — 모던 난수 생성기
  46. 46 Abseil Random Distributions — Uniform·Exponential
  47. 47 Abseil Mocking Random — 테스트 결정성
  48. 48 Abseil Random Seeding·Entropy
  49. 49 absl::int128·uint128 분석
  50. 50 absl::bits — popcount·countl_zero
  51. 51 absl::optional vs std::optional
  52. 52 absl::variant 분석
  53. 53 absl::span 분석
  54. 54 absl::any 분석
  55. 55 absl::compare — three-way 비교
  56. 56 Abseil utility — apply·in_place
  57. 57 Abseil AbslHashValue 분석
  58. 58 Abseil HashState chaining
  59. 59 Abseil Custom hashable 구현
  60. 60 Abseil LOG·VLOG·CHECK 분석
  61. 61 Abseil LogSink 분석
  62. 62 Abseil LogEntry·structured logging
  63. 63 Abseil Stack trace·failure_signal_handler
  64. 64 ABSL_FLAG 정의 분석
  65. 65 Abseil ParseCommandLine 동작
  66. 66 Abseil Flag introspection·validation
  67. 67 Google 스타일의 Abseil 사용 패턴
  68. 68 Abseil 자주 보는 anti-pattern
  69. 69 std → absl 마이그레이션 전략
  70. 70 absl::Cleanup — 함수 종료 시 실행 보장
  71. 71 Abseil algorithm container 확장 — c_sort·c_find_if·c_count_if
  72. 72 absl::function_ref와 any_invocable — 함수 객체 전달의 두 축
  73. 73 absl::bind_front와 Overload — 함수 객체 보조 도구
  74. 74 absl::Cord — 분산 시스템용 대용량 문자열
  75. 75 absl::from_chars·SimpleAtoi — 빠른 숫자 변환
  76. 76 absl::Cord vs std::string — 선택 기준과 메모리 프로파일
  77. 77 absl::GetStackTrace와 Symbolize — crash 시 readable stack
  78. 78 absl::ComputeCrc32c — 하드웨어 가속 체크섬
  79. 79 absl::PeriodicSampler — 적응형 샘플링·jitter 회피