You've already forked pg_probackup
mirror of
https://github.com/postgrespro/pg_probackup.git
synced 2025-07-17 07:22:20 +02:00
PGPRO-533: Add json format for show-config
This commit is contained in:
3
Makefile
3
Makefile
@ -4,7 +4,8 @@ OBJS = src/backup.o src/catalog.o src/configure.o src/data.o \
|
|||||||
src/pg_probackup.o src/restore.o src/show.o src/status.o \
|
src/pg_probackup.o src/restore.o src/show.o src/status.o \
|
||||||
src/util.o src/validate.o src/datapagemap.o src/parsexlog.o \
|
src/util.o src/validate.o src/datapagemap.o src/parsexlog.o \
|
||||||
src/xlogreader.o src/streamutil.o src/receivelog.o \
|
src/xlogreader.o src/streamutil.o src/receivelog.o \
|
||||||
src/archive.o src/utils/parray.o src/utils/pgut.o src/utils/logger.o
|
src/archive.o src/utils/parray.o src/utils/pgut.o src/utils/logger.o \
|
||||||
|
src/utils/json.o
|
||||||
|
|
||||||
EXTRA_CLEAN = src/datapagemap.c src/datapagemap.h src/xlogreader.c \
|
EXTRA_CLEAN = src/datapagemap.c src/datapagemap.h src/xlogreader.c \
|
||||||
src/receivelog.c src/receivelog.h src/streamutil.c src/streamutil.h src/logging.h
|
src/receivelog.c src/receivelog.h src/streamutil.c src/streamutil.h src/logging.h
|
||||||
|
162
src/configure.c
162
src/configure.c
@ -2,19 +2,33 @@
|
|||||||
*
|
*
|
||||||
* configure.c: - manage backup catalog.
|
* configure.c: - manage backup catalog.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2017-2017, Postgres Professional
|
* Copyright (c) 2017-2018, Postgres Professional
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "pg_probackup.h"
|
#include "pg_probackup.h"
|
||||||
|
|
||||||
|
#include "pqexpbuffer.h"
|
||||||
|
|
||||||
|
#include "utils/json.h"
|
||||||
|
|
||||||
|
|
||||||
static void opt_log_level_console(pgut_option *opt, const char *arg);
|
static void opt_log_level_console(pgut_option *opt, const char *arg);
|
||||||
static void opt_log_level_file(pgut_option *opt, const char *arg);
|
static void opt_log_level_file(pgut_option *opt, const char *arg);
|
||||||
static void opt_compress_alg(pgut_option *opt, const char *arg);
|
static void opt_compress_alg(pgut_option *opt, const char *arg);
|
||||||
|
|
||||||
|
static void show_configure_start(void);
|
||||||
|
static void show_configure_end(void);
|
||||||
|
static void show_configure(pgBackupConfig *config);
|
||||||
|
|
||||||
|
static void show_configure_json(pgBackupConfig *config);
|
||||||
|
|
||||||
static pgBackupConfig *cur_config = NULL;
|
static pgBackupConfig *cur_config = NULL;
|
||||||
|
|
||||||
|
static PQExpBufferData show_buf;
|
||||||
|
static int32 json_level = 0;
|
||||||
|
|
||||||
/* Set configure options */
|
/* Set configure options */
|
||||||
int
|
int
|
||||||
do_configure(bool show_only)
|
do_configure(bool show_only)
|
||||||
@ -68,7 +82,7 @@ do_configure(bool show_only)
|
|||||||
config->compress_level = compress_level;
|
config->compress_level = compress_level;
|
||||||
|
|
||||||
if (show_only)
|
if (show_only)
|
||||||
writeBackupCatalogConfig(stderr, config);
|
show_configure(config);
|
||||||
else
|
else
|
||||||
writeBackupCatalogConfigFile(config);
|
writeBackupCatalogConfigFile(config);
|
||||||
|
|
||||||
@ -251,7 +265,6 @@ readBackupCatalogConfigFile(void)
|
|||||||
pgut_readopt(path, options, ERROR);
|
pgut_readopt(path, options, ERROR);
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -271,3 +284,146 @@ opt_compress_alg(pgut_option *opt, const char *arg)
|
|||||||
{
|
{
|
||||||
cur_config->compress_alg = parse_compress_alg(arg);
|
cur_config->compress_alg = parse_compress_alg(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize configure visualization.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
show_configure_start(void)
|
||||||
|
{
|
||||||
|
if (show_format == SHOW_PLAIN)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* For now we need buffer only for JSON format */
|
||||||
|
json_level = 0;
|
||||||
|
initPQExpBuffer(&show_buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Finalize configure visualization.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
show_configure_end(void)
|
||||||
|
{
|
||||||
|
if (show_format == SHOW_PLAIN)
|
||||||
|
return;
|
||||||
|
else
|
||||||
|
appendPQExpBufferChar(&show_buf, '\n');
|
||||||
|
|
||||||
|
fputs(show_buf.data, stdout);
|
||||||
|
termPQExpBuffer(&show_buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Show configure information of pg_probackup.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
show_configure(pgBackupConfig *config)
|
||||||
|
{
|
||||||
|
show_configure_start();
|
||||||
|
|
||||||
|
if (show_format == SHOW_PLAIN)
|
||||||
|
writeBackupCatalogConfig(stdout, config);
|
||||||
|
else
|
||||||
|
show_configure_json(config);
|
||||||
|
|
||||||
|
show_configure_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Json output.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
show_configure_json(pgBackupConfig *config)
|
||||||
|
{
|
||||||
|
PQExpBuffer buf = &show_buf;
|
||||||
|
|
||||||
|
json_add(buf, JT_BEGIN_OBJECT, &json_level);
|
||||||
|
|
||||||
|
json_add_value(buf, "pgdata", config->pgdata, json_level, false);
|
||||||
|
|
||||||
|
json_add_key(buf, "system-identifier", json_level, true);
|
||||||
|
appendPQExpBuffer(buf, UINT64_FORMAT, config->system_identifier);
|
||||||
|
|
||||||
|
/* Connection parameters */
|
||||||
|
if (config->pgdatabase)
|
||||||
|
json_add_value(buf, "pgdatabase", config->pgdatabase, json_level, true);
|
||||||
|
if (config->pghost)
|
||||||
|
json_add_value(buf, "pghost", config->pghost, json_level, true);
|
||||||
|
if (config->pgport)
|
||||||
|
json_add_value(buf, "pgport", config->pgport, json_level, true);
|
||||||
|
if (config->pguser)
|
||||||
|
json_add_value(buf, "pguser", config->pguser, json_level, true);
|
||||||
|
|
||||||
|
/* Replica parameters */
|
||||||
|
if (config->master_host)
|
||||||
|
json_add_value(buf, "master-host", config->master_host, json_level,
|
||||||
|
true);
|
||||||
|
if (config->master_port)
|
||||||
|
json_add_value(buf, "master-port", config->master_port, json_level,
|
||||||
|
true);
|
||||||
|
if (config->master_db)
|
||||||
|
json_add_value(buf, "master-db", config->master_db, json_level, true);
|
||||||
|
if (config->master_user)
|
||||||
|
json_add_value(buf, "master-user", config->master_user, json_level,
|
||||||
|
true);
|
||||||
|
|
||||||
|
if (config->replica_timeout != INT_MIN)
|
||||||
|
{
|
||||||
|
json_add_key(buf, "replica-timeout", json_level, true);
|
||||||
|
appendPQExpBuffer(buf, "%d", config->replica_timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Logging parameters */
|
||||||
|
if (config->log_level_console != INT_MIN)
|
||||||
|
json_add_value(buf, "log-level-console",
|
||||||
|
deparse_log_level(config->log_level_console), json_level,
|
||||||
|
true);
|
||||||
|
if (config->log_level_file != INT_MIN)
|
||||||
|
json_add_value(buf, "log-level-file",
|
||||||
|
deparse_log_level(config->log_level_file), json_level,
|
||||||
|
true);
|
||||||
|
if (config->log_filename)
|
||||||
|
json_add_value(buf, "log-filename", config->log_filename, json_level,
|
||||||
|
true);
|
||||||
|
if (config->error_log_filename)
|
||||||
|
json_add_value(buf, "error-log-filename", config->error_log_filename,
|
||||||
|
json_level, true);
|
||||||
|
if (config->log_directory)
|
||||||
|
json_add_value(buf, "log-directory", config->log_directory, json_level,
|
||||||
|
true);
|
||||||
|
|
||||||
|
if (config->log_rotation_size)
|
||||||
|
{
|
||||||
|
json_add_key(buf, "log-rotation-size", json_level, true);
|
||||||
|
appendPQExpBuffer(buf, "%d", config->log_rotation_size);
|
||||||
|
}
|
||||||
|
if (config->log_rotation_age)
|
||||||
|
{
|
||||||
|
json_add_key(buf, "log-rotation-age", json_level, true);
|
||||||
|
appendPQExpBuffer(buf, "%d", config->log_rotation_age);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Retention parameters */
|
||||||
|
if (config->retention_redundancy)
|
||||||
|
{
|
||||||
|
json_add_key(buf, "retention-redundancy", json_level, true);
|
||||||
|
appendPQExpBuffer(buf, "%u", config->retention_redundancy);
|
||||||
|
}
|
||||||
|
if (config->retention_window)
|
||||||
|
{
|
||||||
|
json_add_key(buf, "retention-window", json_level, true);
|
||||||
|
appendPQExpBuffer(buf, "%u", config->retention_window);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compression parameters */
|
||||||
|
json_add_value(buf, "compress-algorithm",
|
||||||
|
deparse_compress_alg(config->compress_alg), json_level,
|
||||||
|
true);
|
||||||
|
|
||||||
|
json_add_key(buf, "compress-level", json_level, true);
|
||||||
|
appendPQExpBuffer(buf, "%d", config->compress_level);
|
||||||
|
|
||||||
|
json_add(buf, JT_END_OBJECT, &json_level);
|
||||||
|
}
|
||||||
|
232
src/show.c
232
src/show.c
@ -17,6 +17,8 @@
|
|||||||
|
|
||||||
#include "pqexpbuffer.h"
|
#include "pqexpbuffer.h"
|
||||||
|
|
||||||
|
#include "utils/json.h"
|
||||||
|
|
||||||
|
|
||||||
static void show_instance_start(void);
|
static void show_instance_start(void);
|
||||||
static void show_instance_end(void);
|
static void show_instance_end(void);
|
||||||
@ -26,24 +28,9 @@ static int show_backup(time_t requested_backup_id);
|
|||||||
static void show_instance_plain(parray *backup_list, bool show_name);
|
static void show_instance_plain(parray *backup_list, bool show_name);
|
||||||
static void show_instance_json(parray *backup_list);
|
static void show_instance_json(parray *backup_list);
|
||||||
|
|
||||||
/* Json output functions */
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
JT_BEGIN_ARRAY,
|
|
||||||
JT_END_ARRAY,
|
|
||||||
JT_BEGIN_OBJECT,
|
|
||||||
JT_END_OBJECT
|
|
||||||
} JsonToken;
|
|
||||||
|
|
||||||
static void json_add(PQExpBuffer buf, JsonToken type);
|
|
||||||
static void json_add_key(PQExpBuffer buf, const char *name, bool add_comma);
|
|
||||||
static void json_add_value(PQExpBuffer buf, const char *name, const char *value,
|
|
||||||
bool add_comma);
|
|
||||||
|
|
||||||
static PQExpBufferData show_buf;
|
static PQExpBufferData show_buf;
|
||||||
static bool first_instance = true;
|
static bool first_instance = true;
|
||||||
static uint8 json_level = 0;
|
static int32 json_level = 0;
|
||||||
|
|
||||||
int
|
int
|
||||||
do_show(time_t requested_backup_id)
|
do_show(time_t requested_backup_id)
|
||||||
@ -377,115 +364,6 @@ show_instance_plain(parray *backup_list, bool show_name)
|
|||||||
* Json output.
|
* Json output.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void
|
|
||||||
json_add_indent(PQExpBuffer buf)
|
|
||||||
{
|
|
||||||
uint8 i;
|
|
||||||
|
|
||||||
if (json_level == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
appendPQExpBufferChar(buf, '\n');
|
|
||||||
for (i = 0; i < json_level; i++)
|
|
||||||
appendPQExpBufferStr(buf, " ");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
json_add(PQExpBuffer buf, JsonToken type)
|
|
||||||
{
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case JT_BEGIN_ARRAY:
|
|
||||||
appendPQExpBufferChar(buf, '[');
|
|
||||||
json_level++;
|
|
||||||
break;
|
|
||||||
case JT_END_ARRAY:
|
|
||||||
json_level--;
|
|
||||||
if (json_level == 0)
|
|
||||||
appendPQExpBufferChar(buf, '\n');
|
|
||||||
else
|
|
||||||
json_add_indent(buf);
|
|
||||||
appendPQExpBufferChar(buf, ']');
|
|
||||||
break;
|
|
||||||
case JT_BEGIN_OBJECT:
|
|
||||||
json_add_indent(buf);
|
|
||||||
appendPQExpBufferChar(buf, '{');
|
|
||||||
json_level++;
|
|
||||||
break;
|
|
||||||
case JT_END_OBJECT:
|
|
||||||
json_level--;
|
|
||||||
if (json_level == 0)
|
|
||||||
appendPQExpBufferChar(buf, '\n');
|
|
||||||
else
|
|
||||||
json_add_indent(buf);
|
|
||||||
appendPQExpBufferChar(buf, '}');
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
json_add_escaped(PQExpBuffer buf, const char *str)
|
|
||||||
{
|
|
||||||
const char *p;
|
|
||||||
|
|
||||||
appendPQExpBufferChar(buf, '"');
|
|
||||||
for (p = str; *p; p++)
|
|
||||||
{
|
|
||||||
switch (*p)
|
|
||||||
{
|
|
||||||
case '\b':
|
|
||||||
appendPQExpBufferStr(buf, "\\b");
|
|
||||||
break;
|
|
||||||
case '\f':
|
|
||||||
appendPQExpBufferStr(buf, "\\f");
|
|
||||||
break;
|
|
||||||
case '\n':
|
|
||||||
appendPQExpBufferStr(buf, "\\n");
|
|
||||||
break;
|
|
||||||
case '\r':
|
|
||||||
appendPQExpBufferStr(buf, "\\r");
|
|
||||||
break;
|
|
||||||
case '\t':
|
|
||||||
appendPQExpBufferStr(buf, "\\t");
|
|
||||||
break;
|
|
||||||
case '"':
|
|
||||||
appendPQExpBufferStr(buf, "\\\"");
|
|
||||||
break;
|
|
||||||
case '\\':
|
|
||||||
appendPQExpBufferStr(buf, "\\\\");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if ((unsigned char) *p < ' ')
|
|
||||||
appendPQExpBuffer(buf, "\\u%04x", (int) *p);
|
|
||||||
else
|
|
||||||
appendPQExpBufferChar(buf, *p);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
appendPQExpBufferChar(buf, '"');
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
json_add_key(PQExpBuffer buf, const char *name, bool add_comma)
|
|
||||||
{
|
|
||||||
if (add_comma)
|
|
||||||
appendPQExpBufferChar(buf, ',');
|
|
||||||
json_add_indent(buf);
|
|
||||||
|
|
||||||
json_add_escaped(buf, name);
|
|
||||||
appendPQExpBufferStr(buf, ": ");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
json_add_value(PQExpBuffer buf, const char *name, const char *value,
|
|
||||||
bool add_comma)
|
|
||||||
{
|
|
||||||
json_add_key(buf, name, add_comma);
|
|
||||||
json_add_escaped(buf, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Show instance backups in json format.
|
* Show instance backups in json format.
|
||||||
*/
|
*/
|
||||||
@ -499,116 +377,126 @@ show_instance_json(parray *backup_list)
|
|||||||
appendPQExpBufferChar(buf, ',');
|
appendPQExpBufferChar(buf, ',');
|
||||||
|
|
||||||
/* Begin of instance object */
|
/* Begin of instance object */
|
||||||
json_add(buf, JT_BEGIN_OBJECT);
|
json_add(buf, JT_BEGIN_OBJECT, &json_level);
|
||||||
|
|
||||||
json_add_value(buf, "instance", instance_name, false);
|
json_add_value(buf, "instance", instance_name, json_level, false);
|
||||||
json_add_key(buf, "backups", true);
|
json_add_key(buf, "backups", json_level, true);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* List backups.
|
* List backups.
|
||||||
*/
|
*/
|
||||||
json_add(buf, JT_BEGIN_ARRAY);
|
json_add(buf, JT_BEGIN_ARRAY, &json_level);
|
||||||
|
|
||||||
for (i = 0; i < parray_num(backup_list); i++)
|
for (i = 0; i < parray_num(backup_list); i++)
|
||||||
{
|
{
|
||||||
pgBackup *backup = parray_get(backup_list, i);
|
pgBackup *backup = parray_get(backup_list, i);
|
||||||
TimeLineID parent_tli;
|
TimeLineID parent_tli;
|
||||||
char timestamp[100] = "----";
|
char timestamp[100] = "----";
|
||||||
char duration[20] = "----";
|
|
||||||
char data_bytes_str[10] = "----";
|
|
||||||
char lsn[20];
|
char lsn[20];
|
||||||
|
|
||||||
if (i != 0)
|
if (i != 0)
|
||||||
appendPQExpBufferChar(buf, ',');
|
appendPQExpBufferChar(buf, ',');
|
||||||
|
|
||||||
json_add(buf, JT_BEGIN_OBJECT);
|
json_add(buf, JT_BEGIN_OBJECT, &json_level);
|
||||||
|
|
||||||
json_add_value(buf, "id", base36enc(backup->start_time), false);
|
json_add_value(buf, "id", base36enc(backup->start_time), json_level,
|
||||||
|
false);
|
||||||
|
|
||||||
if (backup->parent_backup != 0)
|
if (backup->parent_backup != 0)
|
||||||
json_add_value(buf, "parent-backup-id",
|
json_add_value(buf, "parent-backup-id",
|
||||||
base36enc(backup->parent_backup), true);
|
base36enc(backup->parent_backup), json_level, true);
|
||||||
|
|
||||||
json_add_value(buf, "backup-mode", pgBackupGetBackupMode(backup), true);
|
json_add_value(buf, "backup-mode", pgBackupGetBackupMode(backup),
|
||||||
|
json_level, true);
|
||||||
|
|
||||||
json_add_value(buf, "wal", backup->stream ? "STREAM": "ARCHIVE", true);
|
json_add_value(buf, "wal", backup->stream ? "STREAM": "ARCHIVE",
|
||||||
|
json_level, true);
|
||||||
|
|
||||||
json_add_value(buf, "compress-alg",
|
json_add_value(buf, "compress-alg",
|
||||||
deparse_compress_alg(backup->compress_alg), true);
|
deparse_compress_alg(backup->compress_alg), json_level,
|
||||||
|
true);
|
||||||
|
|
||||||
json_add_key(buf, "compress-level", true);
|
json_add_key(buf, "compress-level", json_level, true);
|
||||||
appendPQExpBuffer(buf, "%d", backup->compress_level);
|
appendPQExpBuffer(buf, "%d", backup->compress_level);
|
||||||
|
|
||||||
json_add_value(buf, "from-replica",
|
json_add_value(buf, "from-replica",
|
||||||
backup->from_replica ? "true" : "false", true);
|
backup->from_replica ? "true" : "false", json_level,
|
||||||
|
true);
|
||||||
|
|
||||||
json_add_key(buf, "block-size", true);
|
json_add_key(buf, "block-size", json_level, true);
|
||||||
appendPQExpBuffer(buf, "%u", backup->block_size);
|
appendPQExpBuffer(buf, "%u", backup->block_size);
|
||||||
|
|
||||||
json_add_key(buf, "xlog-block-size", true);
|
json_add_key(buf, "xlog-block-size", json_level, true);
|
||||||
appendPQExpBuffer(buf, "%u", backup->wal_block_size);
|
appendPQExpBuffer(buf, "%u", backup->wal_block_size);
|
||||||
|
|
||||||
json_add_key(buf, "checksum-version", true);
|
json_add_key(buf, "checksum-version", json_level, true);
|
||||||
appendPQExpBuffer(buf, "%u", backup->checksum_version);
|
appendPQExpBuffer(buf, "%u", backup->checksum_version);
|
||||||
|
|
||||||
json_add_value(buf, "program-version", backup->program_version, true);
|
json_add_value(buf, "program-version", backup->program_version,
|
||||||
json_add_value(buf, "server-version", backup->server_version, true);
|
json_level, true);
|
||||||
|
json_add_value(buf, "server-version", backup->server_version,
|
||||||
|
json_level, true);
|
||||||
|
|
||||||
json_add_key(buf, "current-tli", true);
|
json_add_key(buf, "current-tli", json_level, true);
|
||||||
appendPQExpBuffer(buf, "%d", backup->tli);
|
appendPQExpBuffer(buf, "%d", backup->tli);
|
||||||
|
|
||||||
json_add_key(buf, "parent-tli", true);
|
json_add_key(buf, "parent-tli", json_level, true);
|
||||||
parent_tli = get_parent_tli(backup->tli);
|
parent_tli = get_parent_tli(backup->tli);
|
||||||
appendPQExpBuffer(buf, "%u", parent_tli);
|
appendPQExpBuffer(buf, "%u", parent_tli);
|
||||||
|
|
||||||
snprintf(lsn, lengthof(lsn), "%X/%X",
|
snprintf(lsn, lengthof(lsn), "%X/%X",
|
||||||
(uint32) (backup->start_lsn >> 32), (uint32) backup->start_lsn);
|
(uint32) (backup->start_lsn >> 32), (uint32) backup->start_lsn);
|
||||||
json_add_value(buf, "start-lsn", lsn, true);
|
json_add_value(buf, "start-lsn", lsn, json_level, true);
|
||||||
|
|
||||||
snprintf(lsn, lengthof(lsn), "%X/%X",
|
snprintf(lsn, lengthof(lsn), "%X/%X",
|
||||||
(uint32) (backup->stop_lsn >> 32), (uint32) backup->stop_lsn);
|
(uint32) (backup->stop_lsn >> 32), (uint32) backup->stop_lsn);
|
||||||
json_add_value(buf, "stop-lsn", lsn, true);
|
json_add_value(buf, "stop-lsn", lsn, json_level, true);
|
||||||
|
|
||||||
time2iso(timestamp, lengthof(timestamp), backup->start_time);
|
time2iso(timestamp, lengthof(timestamp), backup->start_time);
|
||||||
json_add_value(buf, "start-time", timestamp, true);
|
json_add_value(buf, "start-time", timestamp, json_level, true);
|
||||||
|
|
||||||
time2iso(timestamp, lengthof(timestamp), backup->end_time);
|
if (backup->end_time)
|
||||||
json_add_value(buf, "end-time", timestamp, true);
|
{
|
||||||
|
time2iso(timestamp, lengthof(timestamp), backup->end_time);
|
||||||
|
json_add_value(buf, "end-time", timestamp, json_level, true);
|
||||||
|
}
|
||||||
|
|
||||||
json_add_key(buf, "recovery-xid", true);
|
json_add_key(buf, "recovery-xid", json_level, true);
|
||||||
appendPQExpBuffer(buf, XID_FMT, backup->recovery_xid);
|
appendPQExpBuffer(buf, XID_FMT, backup->recovery_xid);
|
||||||
|
|
||||||
time2iso(timestamp, lengthof(timestamp), backup->recovery_time);
|
if (backup->recovery_time > 0)
|
||||||
json_add_value(buf, "recovery-time", timestamp, true);
|
|
||||||
|
|
||||||
pretty_size(backup->data_bytes, data_bytes_str,
|
|
||||||
lengthof(data_bytes_str));
|
|
||||||
json_add_value(buf, "data-bytes", data_bytes_str, true);
|
|
||||||
|
|
||||||
pretty_size(backup->wal_bytes, data_bytes_str,
|
|
||||||
lengthof(data_bytes_str));
|
|
||||||
json_add_value(buf, "wal-bytes", data_bytes_str, true);
|
|
||||||
|
|
||||||
if (backup->end_time != (time_t) 0)
|
|
||||||
{
|
{
|
||||||
snprintf(duration, lengthof(duration), "%.*lfs", 0,
|
time2iso(timestamp, lengthof(timestamp), backup->recovery_time);
|
||||||
difftime(backup->end_time, backup->start_time));
|
json_add_value(buf, "recovery-time", timestamp, json_level, true);
|
||||||
json_add_value(buf, "time", duration, true);
|
}
|
||||||
|
|
||||||
|
if (backup->data_bytes != BYTES_INVALID)
|
||||||
|
{
|
||||||
|
json_add_key(buf, "data-bytes", json_level, true);
|
||||||
|
appendPQExpBuffer(buf, INT64_FORMAT, backup->data_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (backup->wal_bytes != BYTES_INVALID)
|
||||||
|
{
|
||||||
|
json_add_key(buf, "wal-bytes", json_level, true);
|
||||||
|
appendPQExpBuffer(buf, INT64_FORMAT, backup->wal_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (backup->primary_conninfo)
|
if (backup->primary_conninfo)
|
||||||
json_add_value(buf, "primary_conninfo", backup->primary_conninfo, true);
|
json_add_value(buf, "primary_conninfo", backup->primary_conninfo,
|
||||||
|
json_level, true);
|
||||||
|
|
||||||
json_add_value(buf, "status", status2str(backup->status), true);
|
json_add_value(buf, "status", status2str(backup->status), json_level,
|
||||||
|
true);
|
||||||
|
|
||||||
json_add(buf, JT_END_OBJECT);
|
json_add(buf, JT_END_OBJECT, &json_level);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* End of backups */
|
/* End of backups */
|
||||||
json_add(buf, JT_END_ARRAY);
|
json_add(buf, JT_END_ARRAY, &json_level);
|
||||||
|
|
||||||
/* End of instance object */
|
/* End of instance object */
|
||||||
json_add(buf, JT_END_OBJECT);
|
json_add(buf, JT_END_OBJECT, &json_level);
|
||||||
|
|
||||||
first_instance = false;
|
first_instance = false;
|
||||||
}
|
}
|
||||||
|
134
src/utils/json.c
Normal file
134
src/utils/json.c
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* json.c: - make json document.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018, Postgres Professional
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "json.h"
|
||||||
|
|
||||||
|
static void json_add_indent(PQExpBuffer buf, int32 level);
|
||||||
|
static void json_add_escaped(PQExpBuffer buf, const char *str);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start or end json token. Currently it is a json object or array.
|
||||||
|
*
|
||||||
|
* Function modifies level value and adds indent if it appropriate.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
json_add(PQExpBuffer buf, JsonToken type, int32 *level)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case JT_BEGIN_ARRAY:
|
||||||
|
appendPQExpBufferChar(buf, '[');
|
||||||
|
*level += 1;
|
||||||
|
break;
|
||||||
|
case JT_END_ARRAY:
|
||||||
|
*level -= 1;
|
||||||
|
if (*level == 0)
|
||||||
|
appendPQExpBufferChar(buf, '\n');
|
||||||
|
else
|
||||||
|
json_add_indent(buf, *level);
|
||||||
|
appendPQExpBufferChar(buf, ']');
|
||||||
|
break;
|
||||||
|
case JT_BEGIN_OBJECT:
|
||||||
|
json_add_indent(buf, *level);
|
||||||
|
appendPQExpBufferChar(buf, '{');
|
||||||
|
*level += 1;
|
||||||
|
break;
|
||||||
|
case JT_END_OBJECT:
|
||||||
|
*level -= 1;
|
||||||
|
if (*level == 0)
|
||||||
|
appendPQExpBufferChar(buf, '\n');
|
||||||
|
else
|
||||||
|
json_add_indent(buf, *level);
|
||||||
|
appendPQExpBufferChar(buf, '}');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add json object's key. If it isn't first key we need to add a comma.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
json_add_key(PQExpBuffer buf, const char *name, int32 level, bool add_comma)
|
||||||
|
{
|
||||||
|
if (add_comma)
|
||||||
|
appendPQExpBufferChar(buf, ',');
|
||||||
|
json_add_indent(buf, level);
|
||||||
|
|
||||||
|
json_add_escaped(buf, name);
|
||||||
|
appendPQExpBufferStr(buf, ": ");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add json object's key and value. If it isn't first key we need to add a
|
||||||
|
* comma.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
json_add_value(PQExpBuffer buf, const char *name, const char *value,
|
||||||
|
int32 level, bool add_comma)
|
||||||
|
{
|
||||||
|
json_add_key(buf, name, level, add_comma);
|
||||||
|
json_add_escaped(buf, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
json_add_indent(PQExpBuffer buf, int32 level)
|
||||||
|
{
|
||||||
|
uint16 i;
|
||||||
|
|
||||||
|
if (level == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
appendPQExpBufferChar(buf, '\n');
|
||||||
|
for (i = 0; i < level; i++)
|
||||||
|
appendPQExpBufferStr(buf, " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
json_add_escaped(PQExpBuffer buf, const char *str)
|
||||||
|
{
|
||||||
|
const char *p;
|
||||||
|
|
||||||
|
appendPQExpBufferChar(buf, '"');
|
||||||
|
for (p = str; *p; p++)
|
||||||
|
{
|
||||||
|
switch (*p)
|
||||||
|
{
|
||||||
|
case '\b':
|
||||||
|
appendPQExpBufferStr(buf, "\\b");
|
||||||
|
break;
|
||||||
|
case '\f':
|
||||||
|
appendPQExpBufferStr(buf, "\\f");
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
appendPQExpBufferStr(buf, "\\n");
|
||||||
|
break;
|
||||||
|
case '\r':
|
||||||
|
appendPQExpBufferStr(buf, "\\r");
|
||||||
|
break;
|
||||||
|
case '\t':
|
||||||
|
appendPQExpBufferStr(buf, "\\t");
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
appendPQExpBufferStr(buf, "\\\"");
|
||||||
|
break;
|
||||||
|
case '\\':
|
||||||
|
appendPQExpBufferStr(buf, "\\\\");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if ((unsigned char) *p < ' ')
|
||||||
|
appendPQExpBuffer(buf, "\\u%04x", (int) *p);
|
||||||
|
else
|
||||||
|
appendPQExpBufferChar(buf, *p);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
appendPQExpBufferChar(buf, '"');
|
||||||
|
}
|
33
src/utils/json.h
Normal file
33
src/utils/json.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* json.h: - prototypes of json output functions.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018, Postgres Professional
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PROBACKUP_JSON_H
|
||||||
|
#define PROBACKUP_JSON_H
|
||||||
|
|
||||||
|
#include "postgres_fe.h"
|
||||||
|
#include "pqexpbuffer.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Json document tokens.
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
JT_BEGIN_ARRAY,
|
||||||
|
JT_END_ARRAY,
|
||||||
|
JT_BEGIN_OBJECT,
|
||||||
|
JT_END_OBJECT
|
||||||
|
} JsonToken;
|
||||||
|
|
||||||
|
extern void json_add(PQExpBuffer buf, JsonToken type, int32 *level);
|
||||||
|
extern void json_add_key(PQExpBuffer buf, const char *name, int32 level,
|
||||||
|
bool add_comma);
|
||||||
|
extern void json_add_value(PQExpBuffer buf, const char *name, const char *value,
|
||||||
|
int32 level, bool add_comma);
|
||||||
|
|
||||||
|
#endif /* PROBACKUP_JSON_H */
|
Reference in New Issue
Block a user