Current section

Files

Jump to
launchdarkly_server_sdk src ldclient_key_redaction.erl
Raw

src/ldclient_key_redaction.erl

%%-------------------------------------------------------------------
%% @doc SDK key redaction utilities
%% @private
%% Provides functions to safely format error reasons and other data
%% to prevent SDK keys from appearing in logs.
%% @end
%%-------------------------------------------------------------------
-module(ldclient_key_redaction).
%% API
-export([format_httpc_error/1]).
-export([format_shotgun_error/1]).
%%===================================================================
%% API
%%===================================================================
%% @doc Format httpc error for safe logging
%%
%% This function provides an abstract representation of httpc error reasons
%% that is safe to log. It only formats known error types. Unknown
%% error types are represented as "unknown error" to prevent accidental
%% exposure of SDK keys, especially in cases where the SDK key might
%% contain special characters like newlines.
%% @end
-spec format_httpc_error(Reason :: term()) -> string().
%% HTTP status codes or other integers are safe to log
format_httpc_error(StatusCode) when is_integer(StatusCode) ->
lists:flatten(io_lib:format("~b", [StatusCode]));
%% Common httpc connection errors
format_httpc_error({failed_connect, _}) ->
"failed to connect";
format_httpc_error(timeout) ->
"timeout opening connection";
format_httpc_error(etimedout) ->
"connection timeout";
format_httpc_error(econnrefused) ->
"connection refused";
format_httpc_error(enetunreach) ->
"network unreachable";
format_httpc_error(ehostunreach) ->
"host unreachable";
format_httpc_error(nxdomain) ->
"domain name not found";
format_httpc_error({tls_alert, {_, Description}}) when is_atom(Description) ->
lists:flatten(io_lib:format("tls_alert: ~p", [Description]));
format_httpc_error({tls_alert, Alert}) ->
lists:flatten(io_lib:format("tls_alert: ~p", [Alert]));
%% Socket errors
format_httpc_error({socket_closed_remotely, _, _}) ->
"socket closed remotely";
format_httpc_error(closed) ->
"connection closed";
format_httpc_error(enotconn) ->
"socket not connected";
%% Known atom errors
format_httpc_error(Reason) when is_atom(Reason) ->
atom_to_list(Reason);
%% For any unknown error type, do not expose details
format_httpc_error(_Reason) ->
"unknown error".
%% @doc Format shotgun/gun error for safe logging
%%
%% This function provides an abstract representation of shotgun error reasons
%% that is safe to log. Shotgun uses gun underneath, so errors can come from gun.
%% Unknown error types are represented as "unknown error".
%% @end
-spec format_shotgun_error(Reason :: term()) -> string().
%% HTTP status codes or other integers are safe to log
format_shotgun_error(StatusCode) when is_integer(StatusCode) ->
lists:flatten(io_lib:format("~b", [StatusCode]));
%% Known shotgun errors from open
format_shotgun_error(gun_open_failed) ->
"connection failed to open";
format_shotgun_error(gun_open_timeout) ->
"timeout opening connection";
%% Gun/socket errors
format_shotgun_error(timeout) ->
"connection timeout";
format_shotgun_error(econnrefused) ->
"connection refused";
format_shotgun_error(enetunreach) ->
"network unreachable";
format_shotgun_error(ehostunreach) ->
"host unreachable";
format_shotgun_error(nxdomain) ->
"domain name not found";
format_shotgun_error({shutdown, _}) ->
"connection shutdown";
format_shotgun_error(normal) ->
"connection closed normally";
format_shotgun_error(closed) ->
"connection closed";
%% Known atom errors
format_shotgun_error(Reason) when is_atom(Reason) ->
atom_to_list(Reason);
%% For any unknown error type, do not expose details
format_shotgun_error(_Reason) ->
"unknown error".