Skip to content
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

HPCC-32465 Add ESP support for trace level #19246

Merged

Conversation

timothyklemm
Copy link
Contributor

@timothyklemm timothyklemm commented Oct 29, 2024

  • Define an ESP process configuration node that supports specification of global TraceFlags values for each ESP.
  • Reserve traceDetail to request a specific trace level (0: none, 1: standard, 2: detailed, 3: max). This replaces acting on the last observed occurrence of either traceNone, traceStandard, traceDetailed, and traceMax.
  • Override default flag settings when not configured and a debug build.

Type of change:

  • This change is a bug fix (non-breaking change which fixes an issue).
  • This change is a new feature (non-breaking change which adds functionality).
  • This change improves the code (refactor or other change that does not change the functionality)
  • This change fixes warnings (the fix does not alter the functionality or the generated code)
  • This change is a breaking change (fix or feature that will cause existing behavior to change).
  • This change alters the query API (existing queries will have to be recompiled)

Checklist:

  • My code follows the code style of this project.
    • My code does not create any new warnings from compiler, build system, or lint.
  • The commit message is properly formatted and free of typos.
    • The commit message title makes sense in a changelog, by itself.
    • The commit is signed.
  • My change requires a change to the documentation.
    • I have updated the documentation accordingly, or...
    • I have created a JIRA ticket to update the documentation.
    • Any new interfaces or exported functions are appropriately commented.
  • I have read the CONTRIBUTORS document.
  • The change has been fully tested:
    • I have added tests to cover my changes.
    • All new and existing tests passed.
    • I have checked that this change does not introduce memory leaks.
    • I have used Valgrind or similar tools to check for potential issues.
  • I have given due consideration to all of the following potential concerns:
    • Scalability
    • Performance
    • Security
    • Thread-safety
    • Cloud-compatibility
    • Premature optimization
    • Existing deployed queries will not be broken
    • This change fixes the problem, not just the symptom
    • The target branch of this pull request is appropriate for such a change.
  • There are no similar instances of the same problem that should be addressed
    • I have addressed them here
    • I have raised JIRA issues to address them separately
  • This is a user interface / front-end modification
    • I have tested my changes in multiple modern browsers
    • The component(s) render as expected

Smoketest:

  • Send notifications about my Pull Request position in Smoketest queue.
  • Test my draft Pull Request.

Testing:

Copy link

Jira Issue: https://hpccsystems.atlassian.net//browse/HPCC-32465

Jirabot Action Result:
Workflow Transition To: Merge Pending
Updated PR

@timothyklemm
Copy link
Contributor Author

timothyklemm commented Oct 31, 2024

@ghalliday you'll notice I've defined my own version of loadTraceFlags for the ESP. I opened https://hpccsystems.atlassian.net/browse/HPCC-32477 to potentially change the jlib implementation. This PR implements the change that Jira suggests.

Also, #19007 is a draft that is stacked on top of this, if you want to see a bigger example of this change in use.

Copy link
Member

@ghalliday ghalliday left a comment

Choose a reason for hiding this comment

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

@timothyklemm The change makes sense, but better would be to enhance the existing loadTraceFlags with a consistent super-set of the functionality. A few other comments on the code as it stands.

void copyTraceFlags(IPropertyTree *legacyEsp, IPropertyTree *appEsp)
{
IPropertyTree *traceFlags = appEsp->queryPropTree(propTraceFlags);
if (traceFlags)
Copy link
Member

Choose a reason for hiding this comment

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

minor: Possibly simpler as

if (traceFlags)
     legacyEsp->setPropTree(propTraceFlags, LINK(match));

(This copyTree function should be moved to jptree.hpp...)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

WIll do.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The simplification of this method is straightforward. Adding a function to jptree ks less so. This function, making assumptions about source and target nodes, is too specialized to belong in jlib. My first thought for generalizing it involves target node, source node, and source path, with the copied node always added as a child of the target. This might not be general enough, if someone might want to specify a target path as well.

If a generalized copy function should be part of this PR, what would your expectation be for its interface/behavior?

Copy link
Member

Choose a reason for hiding this comment

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

There is an existing copyTree function that is clone in workunit.cpp and espp.cpp. It would make sense for this to be migrated into jptree, and for this function to make use of it. Not for this PR though.

{
VStringBuffer attrName("@%s", option.name);
const char* value = nullptr;
if (!(value = ptree->queryProp(attrName)))
Copy link
Member

Choose a reason for hiding this comment

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

style: We generally avoid assignments inside if statements - they are hard to read.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will change.

else // Boolean trace options
{
bool flag = false;
deserializer(value, flag);
Copy link
Member

Choose a reason for hiding this comment

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

minor: Code elsewhere would use strToBool(value). Does the deserializer provide other benefits?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I already had the deserializer for integral trace levels. Just reused it for consistency in the method. Moving logic out to jlib might make the deserializer unpalatable in both cases since its definition is in an ESP header.

{
unsigned level = unsigned(dft & TraceFlags::LevelMask);
dft &= ~TraceFlags::LevelMask;
if (streq(value, "traceStandard"))
Copy link
Member

Choose a reason for hiding this comment

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

tracelevel=standard

would be more intuitive than

tracelevel=traceStandard

also, case insensitive comparison would be more user friendly.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agree.

// ESP process names for use with options mapping
constexpr const char* eclwatchApplication = "eclwatch";
constexpr const char* eclservicesApplication = "eclservices";
constexpr const char* eclqueriesApplication = "eclqueires";
Copy link
Member

Choose a reason for hiding this comment

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

Unused, and has a typo in the string.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I suppose the definitions are premature. I defined them so mapTraceOptions will eventually be able to use different option lists for distinct ESPs. Not sure how many new options will be defined for most platform ESPs, but I have a lot in mind for esdl and esdl-sandbox (when/if we return focus to DESDL) that might also extend into loggingservice.

Are you asking for removal until needed, or is fixing the type sufficient?

Copy link
Member

Choose a reason for hiding this comment

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

I don't mind, probably cleaner to remove.
The danger with adding constants or other items that are not actually used, is that when they come to be used they are not checked, because they are assumed to be correct because they are already checked in, but equally there is a danger that items that are not used aren't checked as carefully when they are merged.

constexpr const char* loggingserviceApplication = "loggingservice";

// Trace options for ESP
constexpr TraceFlags traceLevel = TraceFlags::LevelMask;
Copy link
Member

Choose a reason for hiding this comment

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

This looks is confusing. Why have a constant called traceLevel which is actually a bit mask? It is likely to lead to confusion if there was code which said
if (traceLevel == ....)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Given my use of TRACEOPT, which is its own issue, I needed a flag named traceLevel to build the option. I assigned the mask instead of an individual level hoping it would be clear that the property wasn't tied to that single value. Avoiding TRACEOPT makes this unnecessary.

// Trace option list fragment for options used by most ESPs
#define ESP_OPTIONS_FRAGMENT \
PLATFORM_OPTIONS_FRAGMENT \
TRACEOPT(traceLevel),
Copy link
Member

Choose a reason for hiding this comment

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

I think what you actually want to do is no use TRACEOPT, but use

{ "traceLevel", traceNone },

if you want to support traceLevel.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will change.

}
if (streq(value, "default")) // allow a configuration to explicitly request a default value
continue;
if (streq(option.name, propTraceLevel)) // non-Boolean traceLevel
Copy link
Member

Choose a reason for hiding this comment

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

This logic makes sense, but would probably make more sense added to loadTraceFlags.

I would add add an extra enumeration traceDetail[Level?] = 0xffffffff, and check that value with this processing:

if (option.value == traceDetail)...

(I am suggesting traceDetail rather than traceLevel to avoid clashes with the existing traceLevel option which has different ranges of values?)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agree on loadTraceFlags. With multiple comments here, suggest we fix this here, then it will be easy to lift and shift into jlib.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't understand your intent for traceDetail. Would it replace the string comparison on the name, or would it be in addition to that?

Copy link
Member

Choose a reason for hiding this comment

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

It would replace the comparison on the name.

else if (streq(value, "traceMax"))
dft |= traceMax;
else if (deserializer(value, level) == Deserialization_SUCCESS)
dft |= TraceFlags(level) & TraceFlags::LevelMask;
Copy link
Member

Choose a reason for hiding this comment

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

minor: range checking on level - this could be used to set any of the other flags as well. I suspect that should be blocked.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think it will set any other flags given the application of the level mask, but it does contradict the README which states that all other values are equivalent to traceNone. Will add a range check, and remove the following else block that also contradicts the README by treating all other values as "default".

Copy link
Member

Choose a reason for hiding this comment

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

You are correct, I missed the level mask.

@ghalliday
Copy link
Member

@timothyklemm I only read your comment about the related PR afterwards. I agree, and suggest you make the changes in the lib function.

Copy link
Contributor Author

@timothyklemm timothyklemm left a comment

Choose a reason for hiding this comment

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

@ghalliday I'm clear on most of your feedback, but I do have a couple questions.

constexpr const char* loggingserviceApplication = "loggingservice";

// Trace options for ESP
constexpr TraceFlags traceLevel = TraceFlags::LevelMask;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Given my use of TRACEOPT, which is its own issue, I needed a flag named traceLevel to build the option. I assigned the mask instead of an individual level hoping it would be clear that the property wasn't tied to that single value. Avoiding TRACEOPT makes this unnecessary.

else // Boolean trace options
{
bool flag = false;
deserializer(value, flag);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I already had the deserializer for integral trace levels. Just reused it for consistency in the method. Moving logic out to jlib might make the deserializer unpalatable in both cases since its definition is in an ESP header.

else if (streq(value, "traceMax"))
dft |= traceMax;
else if (deserializer(value, level) == Deserialization_SUCCESS)
dft |= TraceFlags(level) & TraceFlags::LevelMask;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think it will set any other flags given the application of the level mask, but it does contradict the README which states that all other values are equivalent to traceNone. Will add a range check, and remove the following else block that also contradicts the README by treating all other values as "default".

{
unsigned level = unsigned(dft & TraceFlags::LevelMask);
dft &= ~TraceFlags::LevelMask;
if (streq(value, "traceStandard"))
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agree.

}
if (streq(value, "default")) // allow a configuration to explicitly request a default value
continue;
if (streq(option.name, propTraceLevel)) // non-Boolean traceLevel
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agree on loadTraceFlags. With multiple comments here, suggest we fix this here, then it will be easy to lift and shift into jlib.

}
if (streq(value, "default")) // allow a configuration to explicitly request a default value
continue;
if (streq(option.name, propTraceLevel)) // non-Boolean traceLevel
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't understand your intent for traceDetail. Would it replace the string comparison on the name, or would it be in addition to that?

{
VStringBuffer attrName("@%s", option.name);
const char* value = nullptr;
if (!(value = ptree->queryProp(attrName)))
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will change.

// Trace option list fragment for options used by most ESPs
#define ESP_OPTIONS_FRAGMENT \
PLATFORM_OPTIONS_FRAGMENT \
TRACEOPT(traceLevel),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will change.

// ESP process names for use with options mapping
constexpr const char* eclwatchApplication = "eclwatch";
constexpr const char* eclservicesApplication = "eclservices";
constexpr const char* eclqueriesApplication = "eclqueires";
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I suppose the definitions are premature. I defined them so mapTraceOptions will eventually be able to use different option lists for distinct ESPs. Not sure how many new options will be defined for most platform ESPs, but I have a lot in mind for esdl and esdl-sandbox (when/if we return focus to DESDL) that might also extend into loggingservice.

Are you asking for removal until needed, or is fixing the type sufficient?

void copyTraceFlags(IPropertyTree *legacyEsp, IPropertyTree *appEsp)
{
IPropertyTree *traceFlags = appEsp->queryPropTree(propTraceFlags);
if (traceFlags)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

WIll do.

@timothyklemm timothyklemm force-pushed the hpcc-32465-esp-global-trace branch 2 times, most recently from 227fd45 to 8a615da Compare November 22, 2024 20:54
@timothyklemm
Copy link
Contributor Author

@ghalliday I've updated based on your earlier comments. Not sure what to make of the failing test... both GitHub and VS Code handle the internal link that the test claims to be invalid as expected.

@ghalliday
Copy link
Member

@AttilaVamos please can you look at the broken link report. It is from a relative path. Is this a problem with the hyper-link checking?

Copy link
Member

@ghalliday ghalliday left a comment

Choose a reason for hiding this comment

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

Looks good. I think it is worth replacing/updating the loadTraceFlags function with this enhanced version.

void copyTraceFlags(IPropertyTree *legacyEsp, IPropertyTree *appEsp)
{
IPropertyTree *traceFlags = appEsp->queryPropTree(propTraceFlags);
if (traceFlags)
Copy link
Member

Choose a reason for hiding this comment

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

There is an existing copyTree function that is clone in workunit.cpp and espp.cpp. It would make sense for this to be migrated into jptree, and for this function to make use of it. Not for this PR though.

char* endptr = nullptr;
unsigned tmp = strtoul(value, &endptr, 10);
if (endptr && !*endptr && TraceFlags(tmp) <= TraceFlags::LevelMask)
dft |= TraceFlags(tmp) & TraceFlags::LevelMask;
Copy link
Member

Choose a reason for hiding this comment

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

trivial: no need for the mask any more, now the assign is protected.

Copy link
Member

@ghalliday ghalliday left a comment

Choose a reason for hiding this comment

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

Looks good. Please squash and I will merge.

@timothyklemm timothyklemm force-pushed the hpcc-32465-esp-global-trace branch from 67ec81a to 7e44732 Compare December 6, 2024 12:59
@timothyklemm
Copy link
Contributor Author

@ghalliday it's squashed.

@ghalliday
Copy link
Member

@timothyklemm is the first commit required? Please can you separate that out into a separate PR - I would have some related comments that are unrelated to the tracing flags.

@timothyklemm
Copy link
Contributor Author

Oops. There already is a separate PR for the first commit. The two commits are unrelated but combine to form the base for the latest version of the security manager decorator. I forgot to unstack them.

@timothyklemm timothyklemm force-pushed the hpcc-32465-esp-global-trace branch from 7e44732 to caa4517 Compare December 9, 2024 12:42
@timothyklemm
Copy link
Contributor Author

@ghalliday now decoupled from the unrelated commit.

Copy link
Member

@ghalliday ghalliday left a comment

Choose a reason for hiding this comment

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

@timothyklemm one issue spotted on final review.

{
IPropertyTree *traceFlags = appEsp->queryPropTree(propTraceFlags);
if (traceFlags)
legacyEsp->setPropTree(propTraceFlags, traceFlags);
Copy link
Member

Choose a reason for hiding this comment

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

This is missing a LINK(). I think it is likely to cause a crash when esp terminates.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@ghalliday made and squashed the one line change.

- Define an ESP process configuration node that supports specification of global
  TraceFlags values for each ESP.
- Reserve traceDetail to request a specific trace level (0: none, 1: standard,
  2: detailed, 3: max). This replaces acting on the last observed occurrence
  of either traceNone, traceStandard, traceDetailed, and traceMax.
- Override default flag settings when not configured and a debug build.

Signed-off-by: Tim Klemm <tim.klemm@lexisnexisrisk.com>
@timothyklemm timothyklemm force-pushed the hpcc-32465-esp-global-trace branch from caa4517 to 2ad17a1 Compare December 9, 2024 17:58
@ghalliday ghalliday closed this Dec 18, 2024
@ghalliday ghalliday reopened this Dec 18, 2024
Copy link

Jira Issue: https://hpccsystems.atlassian.net//browse/HPCC-32465

Jirabot Action Result:
Workflow Transition To: Merge Pending

@ghalliday ghalliday closed this Jan 6, 2025
@ghalliday ghalliday reopened this Jan 6, 2025
Copy link

github-actions bot commented Jan 6, 2025

Jira Issue: https://hpccsystems.atlassian.net//browse/HPCC-32465

Jirabot Action Result:
Workflow Transition To: Merge Pending

@ghalliday
Copy link
Member

Close and reopened to force all tests to be rerun (to check failures really are false positives)

@ghalliday ghalliday merged commit eb69d88 into hpcc-systems:master Jan 9, 2025
145 of 157 checks passed
Copy link

github-actions bot commented Jan 9, 2025

Jirabot Action Result:
Added fix version: 9.10.0
Workflow Transition: 'Resolve issue'

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.

2 participants