Skip to content

BB2-4572/4911/5193: ITS-log initial integration - #1746

Open
JamesDemeryNava wants to merge 65 commits into
masterfrom
jamesdemery/bb2-4572-its-log-poc
Open

JamesDemeryNava wants to merge 65 commits into
masterfrom
jamesdemery/bb2-4572-its-log-poc

Conversation

@JamesDemeryNava

@JamesDemeryNava JamesDemeryNava commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

JIRA Ticket:
BB2-4572
BB2-4911
BB2-5193

What Does This PR Do?

This PR implements pinging a logging API, currently known as its-log, for specific Blue Button log types. This is part of a larger effort to implement a new data pipeline that is simpler and easier to maintain. We add an environment variable, ITS_LOG_API_ENABLED, which controls whether or not we ping the its-log API.

There is a Confluence page here with details on how to run its-log. You will need to reference that page in order to test this PR. Be sure to download DBeaver before reviewing this and running its-log.

What Should Reviewers Watch For?

  • Was the ITS_LOG_API_ENABLED env var added correctly? Are there any spots i'm missing? To have the env var come through as true, had to run export ITS_LOG_API_ENABLED=True in my terminal, even if I had updated the default value to true in some of the different files
  • Any concerns on the changes to base_ec2.py and base_local.py? We use the ITS_LOG_API_ENABLED env var to control whether or not the its_log_api logging handler is added to the hhs_server and audit loggers (those are the two loggers its_log_api needs to be added to for the log events we want to make it to its-log)
  • I'm not adding the its-log API keys as env vars just yet as we haven't generated them. Thought is we can add those env vars once they've been generated and we have the its-log architecture in place
  • tofu-plan job is failing, likely due to adding the its_log_api_enabled value to the different sops files.
  • The thought here is we can merge this change, as with the env var being false, its-log will not be pinged. Then, we can work on adding the architecture and API keys, and once all of that is in place, we can set the ITS_LOG_API_ENABLED env var to True and start actually pinging the logging API

If you're reviewing this PR, please check for these things in particular:

Validation

  • Pull down this branch, and pull down the latest from main in the cdap repository
    • In a terminal, pull up the cdap repo. You will need to install Go if you have not already. Instructions are here.
    • cd into terraform/services/121-its-log/app in your cdap terminal
    • Run make run. This will run its-log and make it reachable by Blue Button
  • Before running make run-local in a bluebutton-web-server terminal, run export ITS_LOG_API_ENABLED=true in your terminal
  • Run make run-local auth=mock bfd=sbx
    • Via Postman, go through an auth flow, make some API calls
    • Exec into the bb-api container and run:
      • python -m manage log_global_state_metrics --post-to-its-log
      • This will create itslog_summary records, you'll see a bunch of activity in the terminal where you ran its-log
      • You can run log_global_state_metrics without the --post-to-its-log flag and confirm that we do not post to its-log when the flag is not present
    • From the root of the bluebutton-web-server, run:
      • python insights/scripts/encode_etl_post_to_logging_api.py
      • This will create the four ETLs that need to be run as part of this validation, as well as the bb sequence which runs all four of those ETLs
  • Bring the its-log API stack down, continue to run BB API calls:
    • BB should continue to function as expected. You will see logs with the message: "Failed to post to its-log API". The failure is due to its-log not running
    • While its-log is down, open DBeaver
    • Open the .duckdb file. It will be at {HOME}/.its-log/data. The file name will be pupper_{{TODAYS_DATE}}.duckdb
      • You can query the itslog_events table to see the generated events data
      • itslog_etl contains the ETLs and sequence created by running the encode_etl_post_to_logging_api.py script
      • itslog_summary contains the aggregated global and app-level metrics
      • In the same location as the .duckdb file will be four CSV files, created by the db-to-csv ETL
      • Close DBeaver before bringing its-log back up, note how many events are in the itslog_events table
  • Bring the its-log stack back up
    • Bring the BB stack down, run export ITS_LOG_API_ENABLED=false in your terminal and then make run-local
    • Go through in Postman and do a bunch of BB API actions again
    • Bring its-log down:
      • Open the .duckdb file again in DBeaver
      • Confirm no new events have been created in the itslog_events table

What Security Implications Does This PR Have?

Please indicate if this PR does any of the following:

  • Adds any new software dependencies
  • Modifies any security controls
  • Adds new transmission or storage of data
  • Any other changes that could possibly affect security?
  • Yes, one or more of the above security implications apply. This PR must not be merged without the ISSO or team
    security engineer's approval. @sb-DarenDean @sb-benohe checking this because once this is merged and the waffle switch is enabled (which won't happen any time soon, still need to add the terraform code for the new architecture), BB will be pinging a new API to help track metrics data.

Any Migrations?

  • Yes, there are migrations
    • The migrations should be run PRIOR to the code being deployed
    • The migrations should be run AFTER the code is deployed
    • There is a more complicated migration plan (downtime,
      etc)
  • No migrations

…evel ones, calculate in log_global_state_metrics
parser.add_argument(
'-l',
'--post-to-its-log',
action='store_false',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is backwards, passing the argument should store_true

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the argument is not passed, we want it to evaluate as false. From reading the docs and running the log_global_state_metrics command that has worked, so if the argument is passed, it evaluates as true.

group_timestamp = format_timestamp(datetime.now())

report_flag = False if options.get('no_report', None) else True
its_log_flag = False if options.get('post_to_its_log', None) else True

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about this

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Admittedly, this is confusing.

If we set the flag to False, then options.get() will return False. This will then cause the expression to evaluate to True.

If we set the flag to True, then options.get() will return True. This will cause the expression to evaluate to False.

This statement is, I think, inverting the value of the flag passed in.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the testing i've done, if the command has the --post-to-its-log flag, we will ping its-log. If the command is run without the --post-to-its-log flag, we don't post to its-log 🤷 I can try to refactor to make this line less confusing if needed.

Comment thread apps/logging/tests/test_its_log_handler.py Outdated
Comment thread apps/logging/tests/test_its_log_handler.py Outdated
Comment thread apps/logging/tests/test_its_log_handler.py Outdated
Comment thread apps/logging/tests/test_its_log_handler.py Outdated
Comment thread apps/logging/tests/test_its_log_handler.py Outdated
Comment thread apps/logging/its_log_handler.py Outdated
return
payload = self._build_payload(updated_log_message)

threading.Thread(target=self._post_to_api, args=(payload,), daemon=True).start()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we want to create a new thread for each invocation?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading more on this, but I don't think so. There should be some kind of cap. Maybe we limit it to 10 workers initially and see how that performs.

@annamontare-nava annamontare-nava left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few comments to address, and need to get validation working on my end, but otherwise good!

@JamesDemeryNava
JamesDemeryNava marked this pull request as draft October 27, 2026 17:12
@JamesDemeryNava
JamesDemeryNava marked this pull request as ready for review October 28, 2026 14:36
Comment thread apps/logging/loggers.py
try:
result = requests.post(
'http://host.docker.internal:8888/v1/log/create',
headers={'x-api-key': '1234567890123456123456789012345612345678901234561234567890123456'},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See earlier comments.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants