Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 10 additions & 0 deletions openc3/lib/openc3/utilities/env_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# For simple boolean flags
class EnvHelper
def self.enabled?(key)
['true', '1', 'yes', 'on'].include?(ENV[key].to_s.downcase)
end

def self.set?(key)
!ENV[key].to_s.empty?
end
end
19 changes: 8 additions & 11 deletions openc3/lib/openc3/utilities/logger.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@
# This file may also be used under the terms of a commercial license
# if purchased from OpenC3, Inc.

require 'openc3'
require 'openc3/core_ext/class'
require 'openc3/core_ext/time'
require 'openc3/utilities/store_queued'
require 'socket'
require 'logger'
require 'time'
require 'json'
require 'openc3/utilities/env_helper'

module OpenC3
# Supports different levels of logging and only writes if the level
Expand Down Expand Up @@ -201,19 +203,14 @@ def log_message(log_level, message, scope:, user:, type:, url:, other: nil, &blo
@@mutex.synchronize do
data = build_log_data(log_level, message, user: user, type: type, url: url, other: other, &block)
if @stdout
case log_level
when WARN_LEVEL, ERROR_LEVEL, FATAL_LEVEL
if ENV['OPENC3_LOG_STDERR']
$stderr.puts data.as_json().to_json(allow_nan: true)
$stderr.flush
else
$stdout.puts data.as_json().to_json(allow_nan: true)
$stdout.flush
end
# send warning, error, and fatal to stderr if OPENC3_LOG_STDERR env var is set to 1 or true
if [WARN_LEVEL, ERROR_LEVEL, FATAL_LEVEL].include?(log_level) && EnvHelper.enabled?('OPENC3_LOG_STDERR')
io = $stderr
else
$stdout.puts data.as_json().to_json(allow_nan: true)
$stdout.flush
io = $stdout
end
io.puts data.as_json().to_json(allow_nan: true)
io.flush
end
unless @no_store
if scope
Expand Down
41 changes: 40 additions & 1 deletion openc3/python/openc3/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,45 @@
_openc3_keycloak_url = "OPENC3_KEYCLOAK_URL"
_openc3_redis_cluster = "OPENC3_REDIS_CLUSTER"

def get_env_bool(key: str, default: bool = False) -> bool:
"""
Helper function to read boolean values from environment variables.

Treats the following values (case-insensitive) as True:
- 'true'
- '1'
- 'yes'
- 'on'

All other values (including empty string, 'false', '0', etc.) are treated as False.
If the environment variable is not set, returns the default value.

Args:
key: The environment variable name to read
default: The default value to return if the environment variable is not set

Returns:
bool: True if the environment variable is set to a truthy value, False otherwise

Examples:
>>> os.environ['DEBUG'] = 'true'
>>> get_env_bool('DEBUG')
True
>>> get_env_bool('MISSING_VAR', default=True)
True
>>> os.environ['FLAG'] = '1'
>>> get_env_bool('FLAG')
True
>>> os.environ['FLAG'] = 'false'
>>> get_env_bool('FLAG')
False
"""
value = os.environ.get(key)
if value is None:
return default
return value.lower() in ('true', '1', 'yes', 'on')


OPENC3_API_SCHEMA = os.environ.get(_openc3_api_schema, "http")
OPENC3_API_HOSTNAME = os.environ.get(_openc3_api_hostname, "openc3-cosmos-cmd-tlm-api")
try:
Expand Down Expand Up @@ -109,7 +148,7 @@
OPENC3_LOCAL_MODE = os.environ.get(_openc3_local_mode)
OPENC3_LOCAL_MODE_PATH = os.environ.get(_openc3_local_mode_path)
OPENC3_NO_BUCKET_POLICY = os.environ.get(_openc3_no_bucket_policy)
OPENC3_LOG_STDERR = os.environ.get(_openc3_log_stderr)
OPENC3_LOG_STDERR = get_env_bool(_openc3_log_stderr)

OPENC3_SCOPE = os.environ.get(_openc3_scope, "DEFAULT")
OPENC3_API_PASSWORD = os.environ.get(_openc3_api_password)
Expand Down
21 changes: 8 additions & 13 deletions openc3/python/openc3/utilities/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ def fatal(self, message=None, scope=None, user=None, type=LOG, url=None, other=N
other=other,
)

def build_log_data(self, log_level, message, user=None, type=None, url=None, other=None):
def build_log_data(self, log_level: str, message: str | None, user=None, type=None, url=None, other=None):
now_time = datetime.now(timezone.utc)
data = {
"time": int(now_time.timestamp() * 1000000000),
Expand All @@ -228,21 +228,16 @@ def build_log_data(self, log_level, message, user=None, type=None, url=None, oth
data = data | other
return data

def log_message(self, log_level, message, scope, user, type, url, other=None):
def log_message(self, log_level: str, message: str | None, scope, user, type, url, other=None):
with self.instance_mutex:
data = self.build_log_data(log_level, message, user, type, url, other)
if self.stdout:
match log_level:
case "WARN" | "ERROR" | "FATAL":
if OPENC3_LOG_STDERR:
print(json.dumps(data), file=sys.stderr)
sys.stderr.flush()
else:
print(json.dumps(data), file=sys.stdout)
sys.stdout.flush()
case _:
print(json.dumps(data), file=sys.stdout)
sys.stdout.flush()
if (log_level in ['WARN', 'ERROR', 'FATAL']) and OPENC3_LOG_STDERR:
io = sys.stderr
else:
io = sys.stdout
print(json.dumps(data), file=io)
io.flush()
if self.no_store is False:
if scope is not None:
EphemeralStoreQueued.write_topic(f"{scope}__openc3_log_messages", data)
Expand Down
Loading
Loading