{"id":42786,"date":"2026-02-20T08:38:00","date_gmt":"2026-02-20T07:38:00","guid":{"rendered":"https:\/\/www.dbi-services.com\/blog\/?p=42786"},"modified":"2026-03-16T12:40:20","modified_gmt":"2026-03-16T11:40:20","slug":"querying-goldengate-rest-api-log-efficiently","status":"publish","type":"post","link":"https:\/\/www.dbi-services.com\/blog\/querying-goldengate-rest-api-log-efficiently\/","title":{"rendered":"Querying GoldenGate REST API log efficiently"},"content":{"rendered":"\n<p>In this blog post, I will guide you on how to <strong>query<\/strong> the <code>restapi.log<\/code> file of your GoldenGate deployments more efficiently. These logs are a <strong>valuable source of information<\/strong> for GoldenGate administrators but are unfortunately not easy to analyze. In fact, their format is not really suited for a complex analysis. With what I present here, you could improve the <strong>debugging of GoldenGate<\/strong> issues, the <strong>automation of your deployments<\/strong>, or compare the web UI built-in calls with what you want to achieve when <strong><a href=\"https:\/\/www.dbi-services.com\/blog\/goldengate-rest-api-basics-with-python\/\" id=\"42283\" target=\"_blank\" rel=\"noreferrer noopener\">calling the REST API<\/a><\/strong>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-where-can-i-find-the-restapi-log-files\">Where can I find the <code>restapi.log<\/code> files ?<\/h2>\n\n\n\n<p>The <code>restapi.log<\/code> files are located in the <code>var\/log<\/code> folder of your deployment. This is valid for:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>You service manager, for instance <code>\/u01\/app\/oracle\/product\/oggsm\/var\/log\/restapi.log<\/code>.<\/li>\n\n\n\n<li>Any of your deployments, for instance <code>\/u01\/app\/oracle\/product\/ogg_test_01\/var\/log\/restapi.log<\/code>.<\/li>\n<\/ul>\n\n\n\n<p>No matter your installation, you will always have at least two active <code>restapi.log<\/code> files (one for the service manager and one per deployment). Depending on what you want to analyze, you will have to analyze one file or the other.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-what-does-a-restapi-log-entry-look-like\">What does a <code>restapi.log<\/code> entry look like ?<\/h2>\n\n\n\n<p>A typical <code>restapi.log<\/code> entry looks like this :<\/p>\n\n\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; gutter: false; title: ; quick-code: false; notranslate\" title=\"\">\n2026-02-01 07:59:28.566+0000 INFO |RestAPI.adminsrvr | Request #23315: {\n    &quot;context&quot;: {\n        &quot;verb&quot;: &quot;DELETE&quot;,\n        &quot;uri&quot;: &quot;\/services\/v2\/currentuser&quot;,\n        &quot;protocol&quot;: &quot;http&quot;,\n        &quot;host&quot;: &quot;vmogg&quot;,\n        &quot;securityEnabled&quot;: false,\n        ...\n    }\n    Response: {\n        ...\n    }\n<\/pre><\/div>\n\n\n<p>While these logs are very informative, their structure makes it <strong>nearly impossible to analyze<\/strong> efficiently. These logs have no clear structure, even though one entry can be identified by the first line in the form <code>YYYY-MM-DD HH:MM:SS.xxx+0000 INFO |RestAPI.service | Request #req_no: {<\/code>. And to make it even harder, what follows is not a valid JSON object. There are in fact two JSON objects:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>Request #req_no<\/code>, containing the <strong>request<\/strong> that was made.<\/li>\n\n\n\n<li><code>Response<\/code>, containing the <strong>response<\/strong> from the API.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-making-restapi-log-entries-more-readable\">Making <code>restapi.log<\/code> entries more readable<\/h2>\n\n\n\n<p>Below is a Python script that you can use to read and transform your <code>restapi.log<\/code> entries. It takes three arguments:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The path to a specific log file or a log directory. If multiple <code>restapi.log<\/code> files are found with a directory, they will be read in descending order (for instance, first <code>restapi.log.2<\/code>, then <code>restapi.log.1<\/code>, then <code>restapi.log<\/code>)<\/li>\n\n\n\n<li>The path to the new log file which will be generated. This log file which will contain one log entry per line, in a JSON format.<\/li>\n\n\n\n<li><em>[Optional]<\/em> The path to a log file containing all invalid records.<\/li>\n<\/ul>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n#!\/usr\/bin\/env python3\nimport re\nimport sys\nimport json\nimport logging\nfrom pathlib import Path\nfrom datetime import datetime\n\nlogging.basicConfig(\n    level=logging.INFO,\n    format=&quot;%(asctime)s %(levelname)s %(message)s&quot;,\n)\n\nREQUEST_START_RE = re.compile(\n    r&quot;^\\d{4}-\\d{2}-\\d{2} &quot;\n    r&quot;\\d{2}:\\d{2}:\\d{2}\\.\\d{3}\\+\\d{4}\\s+&quot;\n    r&quot;\\w+\\s*\\|\\s*RestAPI\\..*?\\|\\s*Request #\\d+:&quot;\n)\n\n\ndef find_restapi_logs(directory: Path):\n    &quot;&quot;&quot;\n    Return restapi logs ordered from the highest rotation number\n    to the lowest.\n    &quot;&quot;&quot;\n    def sort_key(p: Path):\n        m = re.search(r&quot;\\.(\\d+)$&quot;, p.name)\n        if m:\n            return -int(m.group(1))  # Negative for descending order\n        elif p.name == &quot;restapi.log&quot;:\n            return float(&#039;inf&#039;)  # Ensure restapi.log comes last\n        else:\n            pass  # Any other files are skipped\n\n    files = &#x5B;f for f in directory.glob(&quot;restapi.log*&quot;) if f.is_file()]\n    return sorted(files, key=sort_key)\n\n\ndef parse_json_block(text: str):\n    try:\n        text_clean = re.sub(r&quot;,\\s*(&#x5B;}\\]])&quot;, r&quot;\\1&quot;, text)\n        return json.loads(text_clean)\n    except json.JSONDecodeError as e:\n        raise ValueError(f&quot;JSON parse error: {e}&quot;) from e\n\n\ndef extract_first_json_object(s: str) -&gt; str:\n    depth = 0\n    start = None\n    in_string = False\n    escape = False\n\n    for i, ch in enumerate(s):\n        if in_string:\n            if escape:\n                escape = False\n            elif ch == &quot;\\\\&quot;:\n                escape = True\n            elif ch == &#039;&quot;&#039;:\n                in_string = False\n            continue\n\n        if ch == &#039;&quot;&#039;:\n            in_string = True\n        elif ch == &quot;{&quot;:\n            if depth == 0:\n                start = i\n            depth += 1\n        elif ch == &quot;}&quot;:\n            depth -= 1\n            if depth == 0 and start is not None:\n                return s&#x5B;start:i + 1]\n\n    raise ValueError(&quot;No complete JSON object found&quot;)\n\n\ndef extract_request_response(text_block: str):\n    # Match log header (timestamp, status, service)\n    log_header_match = re.search(\n        r&quot;^(\\d{4}-\\d{2}-\\d{2} &quot;\n        r&quot;\\d{2}:\\d{2}:\\d{2}\\.\\d{3}\\+\\d{4})\\s+&quot;\n        r&quot;(\\w+)\\s*\\|\\s*RestAPI\\.(.*?)\\|&quot;,\n        text_block,\n        re.MULTILINE\n    )\n    restapi_datetime = log_header_match.group(1) if log_header_match else None\n    restapi_status = log_header_match.group(2) if log_header_match else None\n    restapi_service = log_header_match.group(3).strip() if log_header_match else None\n\n    # Convert datetime to epoch\n    restapi_epoch = None\n    if restapi_datetime:\n        try:\n            dt = datetime.strptime(restapi_datetime, &quot;%Y-%m-%d %H:%M:%S.%f%z&quot;)\n            restapi_epoch = int(dt.timestamp())\n        except Exception as e:\n            logging.warning(f&quot;Failed to parse restapi_datetime &#039;{restapi_datetime}&#039;: {e}&quot;)\n\n    # Extract request number\n    reqno_match = re.search(r&quot;Request #(\\d+)&quot;, text_block)\n    restapi_reqno = int(reqno_match.group(1)) if reqno_match else None\n\n    parts = text_block.split(&quot;Response:&quot;, 1)\n\n    request_raw = extract_first_json_object(parts&#x5B;0])\n    request = parse_json_block(request_raw)\n\n    response = None\n    if len(parts) &gt; 1:\n        try:\n            response_raw = extract_first_json_object(parts&#x5B;1])\n            response = parse_json_block(response_raw)\n        except Exception as e:\n            logging.warning(\n                f&quot;Response parse error for reqno {restapi_reqno}: {e}, storing raw&quot;\n            )\n            response = {&quot;raw&quot;: parts&#x5B;1].strip()}\n\n    return {\n        &quot;request&quot;: request,\n        &quot;response&quot;: response,\n        &quot;restapi_datetime&quot;: restapi_datetime,\n        &quot;restapi_epoch&quot;: restapi_epoch,\n        &quot;restapi_status&quot;: restapi_status,\n        &quot;restapi_service&quot;: restapi_service,\n        &quot;restapi_reqno&quot;: restapi_reqno,\n    }\n\n\ndef parse_logs(log_files, output_file: Path, invalid_file: Path = None):\n    total_found = total_written = total_invalid = 0\n    invalid_out = invalid_file.open(&quot;w&quot;, encoding=&quot;utf-8&quot;) if invalid_file else None\n\n    buffer = &#x5B;]\n    in_record = False\n\n    with output_file.open(&quot;w&quot;, encoding=&quot;utf-8&quot;) as out:\n        for log_file in log_files:\n            file_found = file_written = file_invalid = 0\n            logging.info(f&quot;Processing {log_file}&quot;)\n\n            with log_file.open(&quot;r&quot;, encoding=&quot;utf-8&quot;, errors=&quot;ignore&quot;) as f:\n                for line in f:\n                    if REQUEST_START_RE.match(line):\n                        if buffer:\n                            total_found += 1\n                            file_found += 1\n                            record_text = &quot;&quot;.join(buffer)\n                            try:\n                                record = extract_request_response(record_text)\n                                out.write(json.dumps(record, ensure_ascii=False) + &quot;\\n&quot;)\n                                total_written += 1\n                                file_written += 1\n                            except Exception:\n                                total_invalid += 1\n                                file_invalid += 1\n                                if invalid_out:\n                                    invalid_out.write(record_text + &quot;\\n&quot;)\n                        buffer = &#x5B;line]\n                        in_record = True\n                    elif in_record:\n                        buffer.append(line)\n\n            logging.info(\n                f&quot;{log_file.name}: {file_found} found, {file_written} written, {file_invalid} invalid&quot;\n            )\n\n        # Final flush\n        if buffer:\n            total_found += 1\n            try:\n                record = extract_request_response(&quot;&quot;.join(buffer))\n                out.write(json.dumps(record, ensure_ascii=False) + &quot;\\n&quot;)\n                total_written += 1\n            except Exception:\n                total_invalid += 1\n                if invalid_out:\n                    invalid_out.write(&quot;&quot;.join(buffer) + &quot;\\n&quot;)\n\n    if invalid_out:\n        invalid_out.close()\n\n    logging.info(\n        f&quot;DONE: {total_found} records found total, &quot;\n        f&quot;{total_written} written, {total_invalid} invalid&quot;\n    )\n\n\ndef main():\n    if len(sys.argv) &lt; 3:\n        print(f&quot;Usage: {sys.argv&#x5B;0]} &lt;log_directory&gt; &lt;output_ndjson&gt; &#x5B;invalid_file]&quot;)\n        sys.exit(1)\n\n    log_dir = Path(sys.argv&#x5B;1])\n    output_file = Path(sys.argv&#x5B;2])\n    invalid_file = Path(sys.argv&#x5B;3]) if len(sys.argv) &gt; 3 else None\n\n    log_files = find_restapi_logs(log_dir)\n\n    logging.info(f&quot;Input is a directory: {log_dir}&quot;)\n    logging.info(\n        &quot;Using log files (from oldest to newest): &quot;\n        + &quot;, &quot;.join(f.name for f in log_files)\n    )\n\n    parse_logs(log_files, output_file, invalid_file)\n\n\nif __name__ == &quot;__main__&quot;:\n    main()\n\n<\/pre><\/div>\n\n\n<p>You can either analyze all the log files, or just a single file.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Single file analysis\npython3 restapi_to_ndjson.py \/path\/to\/var\/log\/restapi.log restapi.ndjson\n\n# Complete analysis\npython3 restapi_to_ndjson.py \/path\/to\/var\/log restapi.ndjson<\/code><\/pre>\n\n\n\n<p>Here is a usage example of the script given above. It analyzes all <code>restapi.log<\/code> files inside a <code>ogg_test_01<\/code> GoldenGate deployment.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&gt; python3 restapi_to_ndjson.py \/u01\/app\/oracle\/product\/ogg_test_01\/var\/log \/home\/oracle\/restapi_test_01.ndjson\noracle@vmogg:~\/ &#091;OGG] python3 restapi_to_ndjson.py \/u01\/app\/oracle\/product\/ogg_test_01\/var\/log \/home\/oracle\/restapi_test_01.ndjson\n2026-02-14 07:34:14,934 INFO Input is a directory: \/u01\/app\/oracle\/product\/ogg_test_01\/var\/log\n2026-02-14 07:34:14,934 INFO Using log files (from oldest to newest): restapi.log.1, restapi.log.2, restapi.log.3, restapi.log\n2026-02-14 07:34:14,935 INFO Processing \/u01\/app\/oracle\/product\/ogg_test_01\/var\/log\/restapi.log.1\n2026-02-14 07:34:15,807 INFO restapi.log.1: 614 found, 614 written, 0 invalid\n2026-02-14 07:34:15,807 INFO Processing \/u01\/app\/oracle\/product\/ogg_test_01\/var\/log\/restapi.log.2\n2026-02-14 07:34:16,679 INFO restapi.log.2: 740 found, 740 written, 0 invalid\n2026-02-14 07:34:16,679 INFO Processing \/u01\/app\/oracle\/product\/ogg_test_01\/var\/log\/restapi.log.3\n2026-02-14 07:34:17,567 INFO restapi.log.3: 938 found, 938 written, 0 invalid\n2026-02-14 07:34:17,567 INFO Processing \/u01\/app\/oracle\/product\/ogg_test_01\/var\/log\/restapi.log\n2026-02-14 07:34:17,670 INFO restapi.log: 70 found, 70 written, 0 invalid\n2026-02-14 07:34:17,673 INFO DONE: 2363 records found total, 2363 written, 0 invalid<\/code><\/pre>\n\n\n\n<p>This generates a <code>restapi_test_01.ndjson<\/code> file. Let&#8217;s see in the next chapter what one entry looks like.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-log-entry-example\">Log entry example<\/h2>\n\n\n\n<p id=\"h-\">Here is an example of the transformed log entry. It is still not quite readable given the amount of information, but we can at least <strong>filter the logs more efficiently<\/strong> now because of the <code>ndjson<\/code> structure (each line is a valid JSON document).<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&gt; tail -1 restapi_test_01.ndjson\n{\"request\": {\"context\": {\"httpContextKey\": 140656324316240, \"verbId\": 2, \"verb\": \"GET\", \"originalVerb\": \"GET\", \"uri\": \"\/services\/v2\/extracts\", \"protocol\": \"http\", \"headers\": {\"Host\": \"vmogg:7810\", \"User-Agent\": \"python-requests\/2.32.3\", \"Accept-Encoding\": \"gzip, deflate\", \"Accept\": \"application\/json\", \"Connection\": \"keep-alive\", \"Content-Type\": \"application\/json\", \"Authorization\": \"** Masked **\", \"X-OGG-Requestor-Id\": \"\", \"X-OGG-Feature-List\": \"\"}, \"host\": \"vmogg:7810\", \"securityEnabled\": false, \"authorization\": {\"authUserName\": \"ogg\", \"authPassword\": \"** Masked **\", \"authMode\": \"Basic\", \"authUserRole\": \"Security\"}, \"requestId\": 2208, \"uriTemplate\": \"\/services\/{version}\/extracts\", \"catalogUriTemplate\": \"\/services\/{version}\/metadata-catalog\/extracts\"}, \"isScaRequest\": true, \"content\": null, \"parameters\": {\"uri\": {\"version\": \"v2\"}}}, \"response\": {\"context\": {\"httpContextKey\": 140656324316240, \"requestId\": 2208, \"code\": \"200 OK\", \"headers\": {\"Content-Type\": \"application\/json\", \"Set-Cookie\": \"** Masked **\"}, \"Content-Type\": \"application\/json\", \"contentType\": \"application\/json\"}, \"isScaResponse\": true, \"content\": {\"$schema\": \"api:standardResponse\", \"links\": &#091;{\"rel\": \"canonical\", \"href\": \"http:\/\/vmogg:7810\/services\/v2\/extracts\", \"mediaType\": \"application\/json\"}, {\"rel\": \"self\", \"href\": \"http:\/\/vmogg:7810\/services\/v2\/extracts\", \"mediaType\": \"application\/json\"}, {\"rel\": \"describedby\", \"href\": \"http:\/\/vmogg:7810\/services\/v2\/metadata-catalog\/extracts\", \"mediaType\": \"application\/schema+json\"}], \"messages\": &#091;], \"response\": {\"$schema\": \"ogg:collection\", \"items\": &#091;{\"links\": &#091;{\"rel\": \"parent\", \"href\": \"http:\/\/vmogg:7810\/services\/v2\/extracts\", \"mediaType\": \"application\/json\"}, {\"rel\": \"canonical\", \"href\": \"http:\/\/vmogg:7810\/services\/v2\/extracts\/TEST\", \"mediaType\": \"application\/json\"}], \"$schema\": \"ogg:collectionItem\", \"name\": \"TEST\", \"status\": \"running\"}]}}}, \"restapi_datetime\": \"2026-02-09 15:49:26.581+0000\", \"restapi_epoch\": 1770652166, \"restapi_status\": \"INFO\", \"restapi_service\": \"adminsrvr\", \"restapi_reqno\": 294698}<\/code><\/pre>\n\n\n\n<p>Or in a better format, displayed with <code>jq<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>oracle@vmogg:~\/ &#091;OGG] tail -1 restapi_test_01.ndjson | jq\n{\n  \"request\": {\n    \"context\": {\n      \"httpContextKey\": 140656324316240,\n      \"verbId\": 2,\n      \"verb\": \"GET\",\n      ...\n    }\n  },\n  \"response\": {\n    \"context\": {\n      \"httpContextKey\": 140656324316240,\n      \"requestId\": 2208,\n      \"code\": \"200 OK\",\n      ...\n    },\n    \"isScaResponse\": true,\n    \"content\": {\n      \"$schema\": \"api:standardResponse\",\n      ...\n      \"messages\": &#091;],\n      \"response\": {\n        \"items\": &#091;\n          {\n            ...\n            \"$schema\": \"ogg:collectionItem\",\n            \"name\": \"TEST\",\n            \"status\": \"running\"\n          }\n        ]\n      }\n    }\n  },\n  \"restapi_datetime\": \"2026-02-09 15:49:26.581+0000\",\n  \"restapi_epoch\": 1770652166,\n  \"restapi_status\": \"INFO\",\n  \"restapi_service\": \"adminsrvr\",\n  \"restapi_reqno\": 294698\n}<\/code><\/pre>\n\n\n\n<p>Here are the keys available:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>request<\/code>: original Request #reqno element of the log.<\/li>\n\n\n\n<li><code>response<\/code>: original response element of the log.<\/li>\n\n\n\n<li><code>restapi_datetime<\/code>: date string of the log entry.<\/li>\n\n\n\n<li><code>restapi_epoch<\/code>: <code>jq<\/code>-readable timestamp, useful for filtering.<\/li>\n\n\n\n<li><code>restapi_status<\/code>: status displayed in the log header (<code>INFO<\/code>, <code>ERROR<\/code>, etc.)<\/li>\n\n\n\n<li><code>restapi_service<\/code>: GoldenGate service displayed in the log header (<code>adminsrvr<\/code>, <code>distsrvr<\/code>, etc.).<\/li>\n\n\n\n<li><code>restapi_reqno<\/code>: request number.<\/li>\n<\/ul>\n\n\n\n<p>To analyze the results of a call, the interesting part usually lies in the <code>response.content.response.items<\/code> section. But let me present a few of the calls you could make with this.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-examples-of-jq-queries-on-restapi-ndjson\">Examples of <code>jq<\/code> queries on <code>restapi.ndjson<\/code><\/h2>\n\n\n\n<p>There are a ton of very useful call examples. Here are a few interesting ones to use on your GoldenGate deployments. Of course, feel free to build your own !<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Get the <strong>number of each event<\/strong> type.<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>&gt; jq -r '.restapi_status' restapi.ndjson | sort | uniq -c\n     74 ERROR\n   2283 INFO<\/code><\/pre>\n\n\n\n<p>Or if you want a JSON output for monitoring.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>jq -s '\n  group_by(.restapi_status)\n  | map({status: .&#091;0].restapi_status, count: length})\n' restapi.ndjson\n&#091;\n  {\n    \"status\": \"ERROR\",\n    \"count\": 74\n  },\n  {\n    \"status\": \"INFO\",\n    \"count\": 2283\n  }\n]<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Search all logs that do not have the <code>INFO<\/code> status.<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>&gt; jq 'select(.restapi_status != \"INFO\")' restapi.ndjson\n{\n  \"context\": {\n    \"httpContextKey\": 139991246113872,\n    \"verbId\": 2,\n    \"verb\": \"GET\",\n...\n    \"restapi_status\": \"ERROR\",\n    \"restapi_service\": \"adminsrvr\",\n    \"restapi_reqno\": 15\n}<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>As a reminder, the <code>-c<\/code> option of <code>jq<\/code> keeps the results with a single JSON document per line, which is perfect for our use case.<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>&gt; jq -c 'select(.restapi_status != \"INFO\")' restapi.ndjson\n{\"context\":{\"httpContextKey\":139991246113872,\"verbId\":2,\"verb\":\"GET\",...,\"restapi_status\":\"ERROR\",\"restapi_service\":\"adminsrvr\",\"restapi_reqno\":15}<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Retrieve the list of distinct services.<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>&gt; jq -r '.restapi_service' restapi.ndjson | sort | uniq\nadminsrvr\ndistsrvr\npmsrvr\nrecvsrvr<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Retrieve a log count per service.<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>&gt; jq -r '.restapi_service' restapi.ndjson | sort | uniq -c\n    623 adminsrvr\n   1413 distsrvr\n    154 pmsrvr\n    167 recvsrvr<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Retrieve all logs for a specific service.<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>jq -c 'select(.restapi_service == \"adminsrvr\")' restapi.ndjson<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Count occurrences of each <code>HTTP<\/code> verb<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>&gt; jq -r '.request.context.verb' restapi.ndjson | sort | uniq -c\n      6 DELETE\n   1773 GET\n      8 PATCH\n    574 POST\n      2 PUT<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Request all logs for a specific HTTP verb.<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>jq -c 'select(.request.context.verb == \"PUT\")' restapi.ndjson<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Count logs per <code>authUserRole<\/code><\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>&gt; jq -r '.request.context.authorization.authUserRole' restapi.ndjson | sort | uniq -c\n      2 any\n     42 null\n   2319 Security<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Retrieve a specific <code>authUserRole<\/code>. As a reminder, the available roles are <code>Security<\/code>, <code>Administrator<\/code>, <code>Operator<\/code> and <code>User<\/code>.<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>jq -c 'select(.request.context.authorization.authUserRole == \"Operator\")' restapi.ndjson<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Request by <code>authUserName<\/code> (GoldenGate user used when calling the API).<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>jq -r '.request.context.authorization.authUserName' restapi.ndjson | sort | uniq -c<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Specific <code>authUserName<\/code>.<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>jq -c 'select(.request.context.authorization.authUserName == \"ogg\")' restapi.ndjson<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Find logs where the response code is not <code>200 OK<\/code>.<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>jq -c 'select(.response.context.code != \"200 OK\")' restapi.ndjson<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Retrieve logs from the last hour.<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>jq -c --argjson now $(date +%s) '. | select(.restapi_epoch &gt;= ($now - 3600))' restapi.ndjson<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Retrieve logs from the last 24 hours.<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>jq -c --argjson now $(date +%s) '. | select(.restapi_epoch &gt;= ($now - 86400))' restapi.ndjson<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Retrieve a specific request number (<code>reqno<\/code>).<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>jq 'select(.restapi_reqno == 689)' restapi.ndjson<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Retrieve logs between two specific dates.<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>START_EPOCH=$(date -d \"2026-02-14 07:26:01 UTC\" +%s)\nEND_EPOCH=$(date -d \"2026-02-14 07:26:02 UTC\" +%s)\n\njq -c --argjson s \"$START_EPOCH\" --argjson e \"$END_EPOCH\" \\\n   'select(.restapi_epoch &gt;= $s and .restapi_epoch &lt;= $e)' \\\n   restapi.ndjson<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Get a timeline view of your logs, with only the date of the request, the status, the HTTP verb and the URI.<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>jq -r '\"\\(.restapi_datetime) \\(.restapi_status) \\(.request.context.verb) \\(.request.context.uri)\"' restapi.ndjson | head\n2026-01-30 17:02:54.382+0000 INFO POST \/services\/v2\/authorizations\/security\/ogg\n2026-01-30 17:02:58.618+0000 INFO POST \/services\/v2\/config\/files\/GLOBALS\n2026-01-30 17:44:20.879+0000 ERROR GET \/services\/v2\/currentuser\n2026-01-30 17:44:20.898+0000 ERROR GET \/services\/v2\/currentuser\n2026-01-30 17:44:23.309+0000 ERROR GET \/services\/v2\/config\/health\n2026-01-30 17:44:23.309+0000 ERROR GET \/services\/v2\/currentuser\n2026-01-30 17:44:23.382+0000 INFO GET \/services\/v2\/config\/health\n2026-01-30 17:44:23.406+0000 INFO GET \/services\/v2\/config\/health\n2026-01-30 17:44:23.648+0000 INFO GET \/services\/v2\/config\/summary\n2026-01-30 17:44:23.656+0000 INFO GET \/services\/v2\/installation\/services<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Get a count of the most used URI.<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>&gt; jq -r '.request.context.uri' restapi.ndjson | sort | uniq -c | sort -nr | head -10\n    529 \/services\/v2\/commands\/execute\n    454 \/services\/v2\/sources\n    243 \/services\/v2\/config\/summary\n    148 \/services\/v2\/currentuser\n    106 \/services\/v2\/extracts\n     62 \/services\/v2\/stream\n     57 \/services\/v2\/installation\/services\n     52 \/services\/v2\/replicats\n     43 \/services\/v2\/config\/types\/ogg:encryptionProfile\/values\/ogg:encryptionProfile:LocalWallet\n     33 \/services\/v2\/logs\/default<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Get a count of the most used URI templates.<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>&gt; jq -r '.request.context.uriTemplate' restapi.ndjson | sort | uniq -c | sort -nr | head -10\n    529 \/services\/{version}\/commands\/execute\n    454 \/services\/{version}\/sources\n    243 \/services\/{version}\/config\/summary\n    148 \/services\/{version}\/currentuser\n    110 \/services\/{version}\/extracts\n     87 \/services\/{version}\/sources\/{distpath}\n     67 \/services\/{version}\/credentials\/{domain}\/{alias}\n     62 \/services\/{version}\/stream\n     57 \/services\/{version}\/installation\/services\n     53 \/services\/{version}\/config\/types\/{type}\/values\/{value}<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Search for a specific URI<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>jq -c 'select(.request.context.uri == \"\/services\/v2\/sources\")' restapi.ndjson<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Search for a specific URI template<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>jq -c 'select(.request.context.uriTemplate == \"\/services\/{version}\/sources\")' restapi.ndjson<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Number of request per certificate (<code>\/\/ empty<\/code> avoids showing <code>null<\/code> results)<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>&gt; jq -r '.request.parameters.uri.certificate \/\/ empty' restapi.ndjson \\\n| sort | uniq -c\n     11 ogg_23\n     22 ogg_target\n     19 ogg_target2<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Top callers<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>&gt; jq -r '.request.context.headers.\"X-Real-IP\"' restapi.ndjson \\\n| sort | uniq -c | sort -nr\n   1385 null\n    874 10.0.0.1\n     96 vmogg\n      2 10.0.0.2<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Search for the request coming from a specific IP<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>jq -c 'select(.request.context.headers&#091;\"X-Real-IP\"] == \"10.0.0.2\")' restapi.ndjson<\/code><\/pre>\n\n\n\n<p>Of course, feel free to design your own <code>jq<\/code> calls to suit your <code>restapi.log<\/code> analysis or monitoring needs. And for more information on the API, check out my other blogs on the subject, as well as the <a href=\"https:\/\/docs.oracle.com\/en\/database\/goldengate\/core\/26\/oggra\/index.html\" target=\"_blank\" rel=\"noreferrer noopener\">GoldenGate documentation<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this blog post, I will guide you on how to query the restapi.log file of your GoldenGate deployments more efficiently. These logs are a valuable source of information for GoldenGate administrators but are unfortunately not easy to analyze. In fact, their format is not really suited for a complex analysis. With what I present [&hellip;]<\/p>\n","protected":false},"author":152,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[3787,59],"tags":[3572,979,708,328,3573,890,1089,1521,3767],"type_dbi":[3860,3801,3817,3740,3861,3859,3800,3769],"class_list":["post-42786","post","type-post","status-publish","format-standard","hentry","category-goldengate","category-oracle","tag-analysis","tag-api","tag-automation","tag-goldengate","tag-jq","tag-log","tag-python","tag-rest","tag-restapi","type-analysis","type-api","type-automation","type-goldengate","type-jq","type-log","type-rest","type-restapi"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.2 (Yoast SEO v27.2) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Querying GoldenGate REST API log efficiently - dbi Blog<\/title>\n<meta name=\"description\" content=\"Python script and jq calls to transform GoldenGate Microservices REST API log files for analysis and monitoring\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.dbi-services.com\/blog\/querying-goldengate-rest-api-log-efficiently\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Querying GoldenGate REST API log efficiently\" \/>\n<meta property=\"og:description\" content=\"Python script and jq calls to transform GoldenGate Microservices REST API log files for analysis and monitoring\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.dbi-services.com\/blog\/querying-goldengate-rest-api-log-efficiently\/\" \/>\n<meta property=\"og:site_name\" content=\"dbi Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-02-20T07:38:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-03-16T11:40:20+00:00\" \/>\n<meta name=\"author\" content=\"Julien Delattre\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Julien Delattre\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"4 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/querying-goldengate-rest-api-log-efficiently\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/querying-goldengate-rest-api-log-efficiently\/\"},\"author\":{\"name\":\"Julien Delattre\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/764ab019cc9dec42655b4c6b9b8e474e\"},\"headline\":\"Querying GoldenGate REST API log efficiently\",\"datePublished\":\"2026-02-20T07:38:00+00:00\",\"dateModified\":\"2026-03-16T11:40:20+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/querying-goldengate-rest-api-log-efficiently\/\"},\"wordCount\":781,\"commentCount\":0,\"keywords\":[\"analysis\",\"api\",\"Automation\",\"GoldenGate\",\"jq\",\"log\",\"Python\",\"rest\",\"restapi\"],\"articleSection\":[\"GoldenGate\",\"Oracle\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.dbi-services.com\/blog\/querying-goldengate-rest-api-log-efficiently\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/querying-goldengate-rest-api-log-efficiently\/\",\"url\":\"https:\/\/www.dbi-services.com\/blog\/querying-goldengate-rest-api-log-efficiently\/\",\"name\":\"Querying GoldenGate REST API log efficiently - dbi Blog\",\"isPartOf\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#website\"},\"datePublished\":\"2026-02-20T07:38:00+00:00\",\"dateModified\":\"2026-03-16T11:40:20+00:00\",\"author\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/764ab019cc9dec42655b4c6b9b8e474e\"},\"description\":\"Python script and jq calls to transform GoldenGate Microservices REST API log files for analysis and monitoring\",\"breadcrumb\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/querying-goldengate-rest-api-log-efficiently\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.dbi-services.com\/blog\/querying-goldengate-rest-api-log-efficiently\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/querying-goldengate-rest-api-log-efficiently\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Accueil\",\"item\":\"https:\/\/www.dbi-services.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Querying GoldenGate REST API log efficiently\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#website\",\"url\":\"https:\/\/www.dbi-services.com\/blog\/\",\"name\":\"dbi Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.dbi-services.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/764ab019cc9dec42655b4c6b9b8e474e\",\"name\":\"Julien Delattre\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/secure.gravatar.com\/avatar\/a97d00e680bbf237126e24b65281cbcb66cd20bd1ed2d14bf928991b2bf68eb5?s=96&d=mm&r=g\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/a97d00e680bbf237126e24b65281cbcb66cd20bd1ed2d14bf928991b2bf68eb5?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/a97d00e680bbf237126e24b65281cbcb66cd20bd1ed2d14bf928991b2bf68eb5?s=96&d=mm&r=g\",\"caption\":\"Julien Delattre\"},\"url\":\"https:\/\/www.dbi-services.com\/blog\/author\/juliendelattre\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Querying GoldenGate REST API log efficiently - dbi Blog","description":"Python script and jq calls to transform GoldenGate Microservices REST API log files for analysis and monitoring","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.dbi-services.com\/blog\/querying-goldengate-rest-api-log-efficiently\/","og_locale":"en_US","og_type":"article","og_title":"Querying GoldenGate REST API log efficiently","og_description":"Python script and jq calls to transform GoldenGate Microservices REST API log files for analysis and monitoring","og_url":"https:\/\/www.dbi-services.com\/blog\/querying-goldengate-rest-api-log-efficiently\/","og_site_name":"dbi Blog","article_published_time":"2026-02-20T07:38:00+00:00","article_modified_time":"2026-03-16T11:40:20+00:00","author":"Julien Delattre","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Julien Delattre","Est. reading time":"4 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.dbi-services.com\/blog\/querying-goldengate-rest-api-log-efficiently\/#article","isPartOf":{"@id":"https:\/\/www.dbi-services.com\/blog\/querying-goldengate-rest-api-log-efficiently\/"},"author":{"name":"Julien Delattre","@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/764ab019cc9dec42655b4c6b9b8e474e"},"headline":"Querying GoldenGate REST API log efficiently","datePublished":"2026-02-20T07:38:00+00:00","dateModified":"2026-03-16T11:40:20+00:00","mainEntityOfPage":{"@id":"https:\/\/www.dbi-services.com\/blog\/querying-goldengate-rest-api-log-efficiently\/"},"wordCount":781,"commentCount":0,"keywords":["analysis","api","Automation","GoldenGate","jq","log","Python","rest","restapi"],"articleSection":["GoldenGate","Oracle"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.dbi-services.com\/blog\/querying-goldengate-rest-api-log-efficiently\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.dbi-services.com\/blog\/querying-goldengate-rest-api-log-efficiently\/","url":"https:\/\/www.dbi-services.com\/blog\/querying-goldengate-rest-api-log-efficiently\/","name":"Querying GoldenGate REST API log efficiently - dbi Blog","isPartOf":{"@id":"https:\/\/www.dbi-services.com\/blog\/#website"},"datePublished":"2026-02-20T07:38:00+00:00","dateModified":"2026-03-16T11:40:20+00:00","author":{"@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/764ab019cc9dec42655b4c6b9b8e474e"},"description":"Python script and jq calls to transform GoldenGate Microservices REST API log files for analysis and monitoring","breadcrumb":{"@id":"https:\/\/www.dbi-services.com\/blog\/querying-goldengate-rest-api-log-efficiently\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.dbi-services.com\/blog\/querying-goldengate-rest-api-log-efficiently\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.dbi-services.com\/blog\/querying-goldengate-rest-api-log-efficiently\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Accueil","item":"https:\/\/www.dbi-services.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Querying GoldenGate REST API log efficiently"}]},{"@type":"WebSite","@id":"https:\/\/www.dbi-services.com\/blog\/#website","url":"https:\/\/www.dbi-services.com\/blog\/","name":"dbi Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.dbi-services.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/764ab019cc9dec42655b4c6b9b8e474e","name":"Julien Delattre","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/a97d00e680bbf237126e24b65281cbcb66cd20bd1ed2d14bf928991b2bf68eb5?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/a97d00e680bbf237126e24b65281cbcb66cd20bd1ed2d14bf928991b2bf68eb5?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/a97d00e680bbf237126e24b65281cbcb66cd20bd1ed2d14bf928991b2bf68eb5?s=96&d=mm&r=g","caption":"Julien Delattre"},"url":"https:\/\/www.dbi-services.com\/blog\/author\/juliendelattre\/"}]}},"_links":{"self":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/42786","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/users\/152"}],"replies":[{"embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/comments?post=42786"}],"version-history":[{"count":32,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/42786\/revisions"}],"predecessor-version":[{"id":43515,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/42786\/revisions\/43515"}],"wp:attachment":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/media?parent=42786"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/categories?post=42786"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/tags?post=42786"},{"taxonomy":"type","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/type_dbi?post=42786"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}