envoyproxy/envoy
Patterns and conventions
Envoy's C++ has a strong house style. The complete style guide is STYLE.md; this page captures the patterns that come up most often when reading or writing the code.
File layout: interface, impl, mock
Almost every component in Envoy follows a three-way split:
envoy/upstream/cluster_manager.h # Public abstract interface
source/common/upstream/cluster_manager_impl.h
source/common/upstream/cluster_manager_impl.cc
test/mocks/upstream/cluster_manager.h # gMock implementation- The interface header in
envoy/declares pure virtual classes. No method implementations, almost no member fields. - The
*_impl.hdeclares the concrete class that implements the interface, plus its private members. - The
*_impl.ccis where logic lives. - The mock under
test/mocks/mirrors the interface one-for-one withMOCK_METHOD.
When you add a new public interface, add the matching mock in the same PR. Reviewers reject otherwise.
Smart pointer aliases
STYLE.md requires aliasing every smart pointer type:
class Foo;
using FooPtr = std::unique_ptr<Foo>;
using FooSharedPtr = std::shared_ptr<Foo>;
using FooConstSharedPtr = std::shared_ptr<const Foo>;Raw pointers (Foo*) are not aliased.
unique_ptr is preferred over shared_ptr wherever ownership is unambiguous. The factory pattern is used to navigate test cases that need access to memory the production code owns.
Optional references
absl::optional<std::reference_wrapper<T>> has a project-wide alias:
using FooOptRef = OptRef<T>;
using FooOptConstRef = OptRef<const T>;
Function naming
- Functions are
lowerCamelCase. - Classes / structs are
UpperCamelCase. - Member fields end with
_:int connections_per_host_;. - Enum values are
PascalCase:enum class Mode { RoundRobin, LeastRequest };. - Constants are
ConstantVarorCONSTANT_VAR(notkConstantVar). - Type aliases use
using, nottypedef.
Move semantics
When a function takes ownership, prefer && arguments rather than unique_ptr by value:
void onHeaders(Http::HeaderMapPtr&& headers, ...);This forces the caller to write std::move(...) at the call site, making intent obvious.
Exceptions
The data plane is exception-free. New code in the request path may not throw. Existing exception sites are being migrated to absl::StatusOr. Some control plane code still uses exceptions, but new exception sites are discouraged.
When a function can fail, return absl::Status or absl::StatusOr<T>:
absl::StatusOr<RouteConfigConstSharedPtr> resolveRoute(...);The RETURN_IF_NOT_OK, THROW_IF_NOT_OK, and RETURN_IF_NOT_OK_REF macros in source/common/common/statusor.h propagate errors compactly.
Factory registration
Every extension is plugged in through a typed factory. The pattern:
- Declare the abstract factory in
envoy/(e.g.Server::Configuration::NamedHttpFilterConfigFactory). - Implement the concrete factory in
source/extensions/.../config.ccand instantiate the static registration:
REGISTER_FACTORY(MyFilterFactory,
Server::Configuration::NamedHttpFilterConfigFactory);The macro expands to a static Registry<...>::Add<MyFilterFactory> instance whose constructor runs at process start. This is why simply linking an extension into the binary makes it available — the BUILD dependency is the registration.
The registry implementation is in envoy/registry/registry.h.
Threading model
Code on the data path runs on a worker thread. The rules:
- No blocking I/O on the worker.
- No locking, except for read-mostly state through
ThreadLocal::SlotImpl. - Communicate with the main thread via
Event::Dispatcher::post. Never share mutable state directly. - Event-driven only: there are no busy loops. If you need a periodic action, use
Event::Timer.
The full architectural rationale is on the threading model page.
Headers and includes
#pragma once is preferred over header guards.
Includes are grouped by the formatter into:
#include "system_header.h" // <foo>
#include "envoy/...h" // public Envoy headers
#include "source/common/...h" // implementation headers
#include "source/extensions/...h"
#include "absl/...h" // third-party
#include "fmt/format.h"
#include "openssl/...h"tools/code_format/check_format.py enforces ordering and forbids cross-cutting includes (source/extensions/foo.h from source/common/, etc.).
Stat naming
Stat names are dotted, lowercase, deduped through the symbol table. The pattern:
- Define an
ALL_FOO_STATS(COUNTER, GAUGE, HISTOGRAM)X-macro. - Generate a
FooStatsstruct that wraps the counters/gauges/histograms. - Construct it with
POOL_COUNTER(...)etc., scoped to aStats::Scope.
Examples are everywhere; source/server/server.h has the canonical "all server stats" macro at the top.
Logging
ENVOY_LOG(debug, "request received: {}", header_value);
ENVOY_LOG_TO_LOGGER(my_logger, info, "...");
ENVOY_CONN_LOG(trace, "...", connection_);
ENVOY_STREAM_LOG(debug, "...", stream_);Use the highest level that won't be too chatty. Trace is for byte-level debugging.
Comments and documentation
Public API comments use Doxygen with @param, @return, etc. Internal comments may be either // or Doxygen at developer discretion. Comment blocks gated by clang-format off/clang-format on are allowed but discouraged.
Banned constructs
tools/code_format/check_format.py enforces a long list of bans. Highlights:
using namespace ...(exceptEnvoy::ProtobufWktin narrow places).- Non-PoD globals (use
MUTABLE_CONSTRUCT_ON_FIRST_USEor static-initialization-on-first-use). whitelist,blacklist,master,slaveper the inclusive language policy.- Direct calls to
RELEASE_ASSERT(false, ...)instead ofENVOY_BUG. - Direct manipulation of
std::condition_variableinstead ofThread::CondVar. - Bare
std::regex(useRegex::Engine::matcherinstead). - Bare
std::random_deviceand friends (must go throughRandom::RandomGenerator).
API conventions
Anything in api/ follows protobuf style with project-specific overlays. The full rules are in api/STYLE.md. Highlights:
- Versioning:
v3is current, new fields land asBootstrap.foorather than a new version unless they break compatibility. - Field numbers are tightly scoped — never renumber, never reuse.
- Validation rules use
[(validate.rules) = ...](protoc-gen-validate). - Comments at the proto level are user-facing documentation.
See also
STYLE.md(canonical)- Threading model
- Tooling
- Testing
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.