Skip to content

CDRIVER-3775: Implement standardised logging POC #684

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 33 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
60fe054
WIP: first stab at structured logging
alcaeus Sep 9, 2020
d5556b0
Make context generation lazy to save on resources
alcaeus Sep 11, 2020
66e4d31
Remove syslog and log to stderr
alcaeus Sep 11, 2020
7f9b9ef
Don't clear context_data
alcaeus Sep 11, 2020
129b68f
Update signatures
alcaeus Sep 15, 2020
237b8e2
Explicitly track whether context was already built
alcaeus Sep 15, 2020
ab9cf4b
Fix coding style
alcaeus Sep 15, 2020
5323029
Extract command logging and add structs
alcaeus Sep 17, 2020
9c578c5
Refactor signatures and log all command results
alcaeus Sep 17, 2020
aa1e29d
Keep default logger private
alcaeus Sep 18, 2020
e5f6785
Rename context to message
alcaeus Sep 18, 2020
71614d9
Add tests for structured logging
alcaeus Sep 18, 2020
18302f2
Run clang-format
alcaeus Sep 18, 2020
123dde7
Update copyright years
alcaeus Sep 18, 2020
6ca8dd7
Add rudimentary documentation for new public API
alcaeus Sep 18, 2020
a6a771f
Fix wrong log message for command failed log entry
alcaeus Sep 22, 2020
1c82483
Add spec compliant default logger
alcaeus Sep 22, 2020
622966c
Run clang-format
alcaeus Sep 22, 2020
eab01b2
Log client creation
alcaeus Sep 22, 2020
7f5d27e
Fix suggestions from code review
alcaeus Sep 24, 2020
34387eb
Remove unused variable
alcaeus Sep 24, 2020
48910cd
Remove union in favour of void *
alcaeus Sep 25, 2020
3660444
Use lowercase test names
alcaeus Sep 25, 2020
0931b30
Free allocated memory in tests
alcaeus Sep 25, 2020
6fab78f
Fix wrong location for imports
alcaeus Sep 25, 2020
67a7f6f
Attach OP_MSG document sequences when logging commands
alcaeus Sep 25, 2020
9f89f7f
Remove mixed declaration and code
alcaeus Sep 25, 2020
0e15e68
Fix single-line comments
alcaeus Sep 28, 2020
7c94179
Fix more single line comments
alcaeus Sep 30, 2020
9e9110b
Update logged fields to latest spec version
alcaeus Oct 8, 2020
992ec66
Implement BSON serializer that limit serialized string length
alcaeus Oct 13, 2020
4b499f4
Use maximum document length setting when logging documents
alcaeus Oct 13, 2020
e526e11
Fix wrong comment style
alcaeus Oct 13, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions src/libbson/src/bson/bson-types.h
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,40 @@ typedef struct _bson_error_t {
} bson_error_t BSON_ALIGNED_END (8);


/**
* BSON_MAX_LEN_UNLIMITED
*
* Denotes unlimited length limit when converting BSON to JSON.
*/
#define BSON_MAX_LEN_UNLIMITED -1

/**
* bson_json_mode_t:
*
* This enumeration contains the different modes to serialize BSON into extended
* JSON.
*/
typedef enum {
BSON_JSON_MODE_LEGACY,
BSON_JSON_MODE_CANONICAL,
BSON_JSON_MODE_RELAXED,
} bson_json_mode_t;

/**
* bson_json_opts_t:
*
* This structure is used to pass options for serializing BSON into extended
* JSON to the respective serialization methods.
*
* max_len can be either a non-negative integer, or BSON_MAX_LEN_UNLIMITED to
* set no limit for serialization length.
*/
typedef struct {
bson_json_mode_t mode;
int32_t max_len;
} bson_json_opts_t;


BSON_STATIC_ASSERT2 (error_t, sizeof (bson_error_t) == 512);


Expand Down
146 changes: 116 additions & 30 deletions src/libbson/src/bson/bson.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,6 @@ typedef enum {
} bson_validate_phase_t;


typedef enum {
BSON_JSON_MODE_LEGACY,
BSON_JSON_MODE_CANONICAL,
BSON_JSON_MODE_RELAXED,
} bson_json_mode_t;


/*
* Structures.
*/
Expand All @@ -69,6 +62,8 @@ typedef struct {
uint32_t depth;
bson_string_t *str;
bson_json_mode_t mode;
int32_t max_len;
bool max_len_reached;
} bson_json_state_t;


Expand All @@ -88,7 +83,8 @@ _bson_as_json_visit_document (const bson_iter_t *iter,
static char *
_bson_as_json_visit_all (const bson_t *bson,
size_t *length,
bson_json_mode_t mode);
bson_json_mode_t mode,
int32_t max_len);

/*
* Globals.
Expand Down Expand Up @@ -2583,7 +2579,7 @@ _bson_as_json_visit_int64 (const bson_iter_t *iter,

if (state->mode == BSON_JSON_MODE_CANONICAL) {
bson_string_append_printf (
state->str, "{ \"$numberLong\" : \"%" PRId64 "\"}", v_int64);
state->str, "{ \"$numberLong\" : \"%" PRId64 "\" }", v_int64);
} else {
bson_string_append_printf (state->str, "%" PRId64, v_int64);
}
Expand Down Expand Up @@ -2715,8 +2711,8 @@ _bson_as_json_visit_binary (const bson_iter_t *iter,

b64_len = COMMON_PREFIX (bson_b64_ntop_calculate_target_size (v_binary_len));
b64 = bson_malloc0 (b64_len);
BSON_ASSERT (
COMMON_PREFIX (bson_b64_ntop (v_binary, v_binary_len, b64, b64_len) != -1));
BSON_ASSERT (COMMON_PREFIX (
bson_b64_ntop (v_binary, v_binary_len, b64, b64_len) != -1));

if (state->mode == BSON_JSON_MODE_CANONICAL ||
state->mode == BSON_JSON_MODE_RELAXED) {
Expand Down Expand Up @@ -2922,6 +2918,10 @@ _bson_as_json_visit_before (const bson_iter_t *iter,
bson_json_state_t *state = data;
char *escaped;

if (state->max_len_reached) {
return true;
}

if (state->count) {
bson_string_append (state->str, ", ");
}
Expand All @@ -2944,6 +2944,30 @@ _bson_as_json_visit_before (const bson_iter_t *iter,
}


static bool
_bson_as_json_visit_after (const bson_iter_t *iter, const char *key, void *data)
{
bson_json_state_t *state = data;

if (state->max_len == BSON_MAX_LEN_UNLIMITED) {
return false;
}

if (state->str->len >= state->max_len) {
state->max_len_reached = true;

if (state->str->len > state->max_len) {
/* Truncate string to maximum length */
bson_string_truncate (state->str, state->max_len);
}

return true;
}

return false;
}


static void
_bson_as_json_visit_corrupt (const bson_iter_t *iter, void *data)
{
Expand Down Expand Up @@ -3018,35 +3042,41 @@ _bson_as_json_visit_codewscope (const bson_iter_t *iter,
bson_json_state_t *state = data;
char *code_escaped;
char *scope;
int32_t max_scope_len = BSON_MAX_LEN_UNLIMITED;

code_escaped = bson_utf8_escape_for_json (v_code, v_code_len);
if (!code_escaped) {
return true;
}

bson_string_append (state->str, "{ \"$code\" : \"");
bson_string_append (state->str, code_escaped);
bson_string_append (state->str, "\", \"$scope\" : ");

bson_free (code_escaped);

/* Encode scope with the same mode */
scope = _bson_as_json_visit_all (v_scope, NULL, state->mode);
if (state->max_len != BSON_MAX_LEN_UNLIMITED) {
max_scope_len = BSON_MAX (0, state->max_len - state->str->len);
}

scope = _bson_as_json_visit_all (v_scope, NULL, state->mode, max_scope_len);

if (!scope) {
bson_free (code_escaped);
return true;
}

bson_string_append (state->str, "{ \"$code\" : \"");
bson_string_append (state->str, code_escaped);
bson_string_append (state->str, "\", \"$scope\" : ");
bson_string_append (state->str, scope);
bson_string_append (state->str, " }");

bson_free (code_escaped);
bson_free (scope);

return false;
}


static const bson_visitor_t bson_as_json_visitors = {
_bson_as_json_visit_before, NULL, /* visit_after */
_bson_as_json_visit_before, _bson_as_json_visit_after,
_bson_as_json_visit_corrupt, _bson_as_json_visit_double,
_bson_as_json_visit_utf8, _bson_as_json_visit_document,
_bson_as_json_visit_array, _bson_as_json_visit_binary,
Expand Down Expand Up @@ -3081,9 +3111,24 @@ _bson_as_json_visit_document (const bson_iter_t *iter,
child_state.str = bson_string_new ("{ ");
child_state.depth = state->depth + 1;
child_state.mode = state->mode;
child_state.max_len = BSON_MAX_LEN_UNLIMITED;
if (state->max_len != BSON_MAX_LEN_UNLIMITED) {
child_state.max_len = BSON_MAX (0, state->max_len - state->str->len);
}

child_state.max_len_reached = child_state.max_len == 0;

if (bson_iter_visit_all (&child, &bson_as_json_visitors, &child_state)) {
if (child_state.max_len_reached) {
bson_string_append (state->str, child_state.str->str);
}

bson_string_free (child_state.str, true);
return true;

/* If max_len was reached, we return a success state to ensure that
* VISIT_AFTER is still called
*/
return !child_state.max_len_reached;
}

bson_string_append (child_state.str, " }");
Expand Down Expand Up @@ -3114,9 +3159,24 @@ _bson_as_json_visit_array (const bson_iter_t *iter,
child_state.str = bson_string_new ("[ ");
child_state.depth = state->depth + 1;
child_state.mode = state->mode;
child_state.max_len = BSON_MAX_LEN_UNLIMITED;
if (state->max_len != BSON_MAX_LEN_UNLIMITED) {
child_state.max_len = BSON_MAX (0, state->max_len - state->str->len);
}

child_state.max_len_reached = child_state.max_len == 0;

if (bson_iter_visit_all (&child, &bson_as_json_visitors, &child_state)) {
if (child_state.max_len_reached) {
bson_string_append (state->str, child_state.str->str);
}

bson_string_free (child_state.str, true);
return true;

/* If max_len was reached, we return a success state to ensure that
* VISIT_AFTER is still called
*/
return !child_state.max_len_reached;
}

bson_string_append (child_state.str, " ]");
Expand All @@ -3131,7 +3191,8 @@ _bson_as_json_visit_array (const bson_iter_t *iter,
static char *
_bson_as_json_visit_all (const bson_t *bson,
size_t *length,
bson_json_mode_t mode)
bson_json_mode_t mode,
int32_t max_len)
{
bson_json_state_t state;
bson_iter_t iter;
Expand Down Expand Up @@ -3161,9 +3222,12 @@ _bson_as_json_visit_all (const bson_t *bson,
state.depth = 0;
state.err_offset = &err_offset;
state.mode = mode;
state.max_len = max_len;
state.max_len_reached = false;

if (bson_iter_visit_all (&iter, &bson_as_json_visitors, &state) ||
err_offset != -1) {
if ((bson_iter_visit_all (&iter, &bson_as_json_visitors, &state) ||
err_offset != -1) &&
!state.max_len_reached) {
/*
* We were prematurely exited due to corruption or failed visitor.
*/
Expand All @@ -3174,7 +3238,9 @@ _bson_as_json_visit_all (const bson_t *bson,
return NULL;
}

bson_string_append (state.str, " }");
if (!state.max_len_reached) {
bson_string_append (state.str, " }");
}

if (length) {
*length = state.str->len;
Expand All @@ -3184,24 +3250,39 @@ _bson_as_json_visit_all (const bson_t *bson,
}


char *
bson_as_json_with_opts (const bson_t *bson,
size_t *length,
const bson_json_opts_t *opts)
{
return _bson_as_json_visit_all (bson, length, opts->mode, opts->max_len);
}


char *
bson_as_canonical_extended_json (const bson_t *bson, size_t *length)
{
return _bson_as_json_visit_all (bson, length, BSON_JSON_MODE_CANONICAL);
const bson_json_opts_t opts = {BSON_JSON_MODE_CANONICAL,
BSON_MAX_LEN_UNLIMITED};
return bson_as_json_with_opts (bson, length, &opts);
}


char *
bson_as_json (const bson_t *bson, size_t *length)
{
return _bson_as_json_visit_all (bson, length, BSON_JSON_MODE_LEGACY);
const bson_json_opts_t opts = {BSON_JSON_MODE_LEGACY,
BSON_MAX_LEN_UNLIMITED};
return bson_as_json_with_opts (bson, length, &opts);
}


char *
bson_as_relaxed_extended_json (const bson_t *bson, size_t *length)
{
return _bson_as_json_visit_all (bson, length, BSON_JSON_MODE_RELAXED);
const bson_json_opts_t opts = {BSON_JSON_MODE_RELAXED,
BSON_MAX_LEN_UNLIMITED};
return bson_as_json_with_opts (bson, length, &opts);
}


Expand Down Expand Up @@ -3236,9 +3317,12 @@ bson_array_as_json (const bson_t *bson, size_t *length)
state.depth = 0;
state.err_offset = &err_offset;
state.mode = BSON_JSON_MODE_LEGACY;
state.max_len = BSON_MAX_LEN_UNLIMITED;
state.max_len_reached = false;

if (bson_iter_visit_all (&iter, &bson_as_json_visitors, &state) ||
err_offset != -1) {
if ((bson_iter_visit_all (&iter, &bson_as_json_visitors, &state) ||
err_offset != -1) &&
!state.max_len_reached) {
/*
* We were prematurely exited due to corruption or failed visitor.
*/
Expand All @@ -3249,7 +3333,9 @@ bson_array_as_json (const bson_t *bson, size_t *length)
return NULL;
}

bson_string_append (state.str, " ]");
if (!state.max_len_reached) {
bson_string_append (state.str, " ]");
}

if (length) {
*length = state.str->len;
Expand Down
25 changes: 25 additions & 0 deletions src/libbson/src/bson/bson.h
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,31 @@ bson_validate_with_error (const bson_t *bson,
bson_error_t *error);


/**
* bson_as_json_with_opts:
* @bson: A bson_t.
* @length: A location for the string length, or NULL.
* @opts: A bson_t_json_opts_t defining options for the conversion
*
* Creates a new string containing @bson in the selected JSON format,
* conforming to the MongoDB Extended JSON Spec:
*
* github.com/mongodb/specifications/blob/master/source/extended-json.rst
*
* The caller is responsible for freeing the resulting string. If @length is
* non-NULL, then the length of the resulting string will be placed in @length.
*
* See http://docs.mongodb.org/manual/reference/mongodb-extended-json/ for
* more information on extended JSON.
*
* Returns: A newly allocated string that should be freed with bson_free().
*/
BSON_EXPORT (char *)
bson_as_json_with_opts (const bson_t *bson,
size_t *length,
const bson_json_opts_t *opts);


/**
* bson_as_canonical_extended_json:
* @bson: A bson_t.
Expand Down
Loading