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

add config to autoformat stackdriver trace #260

Merged
merged 19 commits into from
Sep 29, 2018

Conversation

StevenYCChou
Copy link
Contributor

No description provided.

@@ -393,6 +399,10 @@ module InternalConstants
config_param :monitoring_type, :string,
:default => Monitoring::PrometheusMonitoringRegistry.name

# Whether to autoformat value of "logging.googleapis.com/trace" to
# LogEntry.Trace.
config_param :enable_stackdriver_trace_autoformat, :bool, :default => true
Copy link
Member

Choose a reason for hiding this comment

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

Let's use the imperative form: autoformat_stackdriver_trace.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

makes sense. updated.

trace = record.delete(@trace_key)
entry.trace = trace if trace
if trace
if @enable_stackdriver_trace_autoformat &&
Copy link
Member

Choose a reason for hiding this comment

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

Let's extract this into a compute_trace method and leave this line as:

entry.trace = compute_trace(trace) if trace

Copy link
Contributor Author

Choose a reason for hiding this comment

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

added

config: APPLICATION_DEFAULT_CONFIG
},
{
config: 'enable_stackdriver_trace_autoformat true'
Copy link
Member

Choose a reason for hiding this comment

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

Please extract this and the next config string into constants, and define them in terms of APPLICATION_DEFAULT_CONFIG.

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

added configs into constant.


verify_log_entries(1, COMPUTE_PARAMS, 'jsonPayload') do |entry|
expected_trace = \
"projects/#{d.instance.project_id}" \
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 a change detector test (it replicates the code under test). Please use the literal value. Better yet, define two constants, one for the compliant trace, and one for the non-compliant trace.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, instead of d.instance.project_id, we could just use PROJECT, which is defined in the constants.rb file.

Copy link
Member

Choose a reason for hiding this comment

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

I was proposing the FULL_STACKDRIVER_TRACE and NON_STACKDRIVER_TRACE, same as you... If we define one in terms of the other, we can even use FULL_STACKDRIVER_TRACE as the expected value here...

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 full trace here depends on the project_id of driver. If we change the whole trace into constant, It's unclear how that project_id in full trace comes from. I think it's hiding details into constant.

I think this project_id is local to this scope under the driver here. WDYT?

Copy link
Member

Choose a reason for hiding this comment

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

The point is that the tests should be checking complete expected values. If you expect the resulting trace to have a particular project id, the constant should have that. I was suggesting defining the FULL_STACKDRIVER_TRACE as:

NON_STACKDRIVER_TRACE = "1234567890abcdef1234567890abcdef".freeze
FULL_STACKDRIVER_TRACE = "projects/#{PROJECT_ID}/traces/#{NON_STACKDRIVER_TRACE}".freeze

in constants.rb.

config: APPLICATION_DEFAULT_CONFIG
},
{
config: 'enable_stackdriver_trace_autoformat true'
Copy link
Contributor

Choose a reason for hiding this comment

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

@@ -338,6 +338,81 @@ def test_structured_payload_log
end
end

def test_stackdriver_trace_format_compliant_trace
full_stackdriver_trace = \
Copy link
Contributor

Choose a reason for hiding this comment

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

Constant FULL_STACKDRIVER_TRACE?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ditto - I think the full trace is project-dependent, not constant value.

Copy link
Member

Choose a reason for hiding this comment

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

The project we feed into the tests is a constant, though... So we could construct the full expected value as a constant.

end

def test_autoformat_enabled_with_stackdriver_trace_format_noncompliant_trace
non_stackdriver_trace_compliant_trace = '1234567890abcdef1234567890abcdef'
Copy link
Contributor

Choose a reason for hiding this comment

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

Constant NON_STACKDRIVER_TRACE?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Change this value into constant, but use the name as NON_STACKDRIVER_TRACE_COMPLIANT_TRACE as this value can be a "Stackdriver Trace", but it is just not compliant to enable cross reference between Stackdriver Logging & Trace.

d.run

verify_log_entries(1, COMPUTE_PARAMS, 'jsonPayload') do |entry|
assert_equal full_stackdriver_trace, entry['trace']
Copy link
Contributor

Choose a reason for hiding this comment

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

assert_equal can take a third parameter as the error message when the assertion fails. In order to help with debugging, we could something like:

assert_equal full_stackdriver_trace, entry['trace'],
             "test_params #{test_params} failed with entry #{entry}."

Same for below.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

added more informative error messages.

end

def test_autoformat_disabled_with_stackdriver_trace_format_noncompliant_trace
config = 'enable_stackdriver_trace_autoformat false'
Copy link
Contributor

Choose a reason for hiding this comment

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

Constant AUTOFORMAT_STACKDRIVER_TRACE_DISABLED_CONFIG?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated.


def test_autoformat_disabled_with_stackdriver_trace_format_noncompliant_trace
config = 'enable_stackdriver_trace_autoformat false'
non_stackdriver_trace_compliant_trace = '1234567890abcdef1234567890abcdef'
Copy link
Contributor

Choose a reason for hiding this comment

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

Constant NON_STACKDRIVER_TRACE?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated - see comment above

trace = record.delete(@trace_key)
entry.trace = trace if trace
if trace
Copy link
Contributor

Choose a reason for hiding this comment

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

We probably wanna check against empty strings as well? I'm leaning towards not formatting the field if it comes as an empty string. WDYT?

BTW, Ruby will take if <empty_string> as true.

$ irb
2.4.3 :001 > empty_string = ""
 => ""
2.4.3 :002 > if empty_string then true else false end
 => true

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

Fun read. Oh Ruby... shoot me:

$ irb
2.4.3 :001 > if 0 then true else false end
 => true

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@@ -338,6 +338,81 @@ def test_structured_payload_log
end
end

def test_stackdriver_trace_format_compliant_trace
Copy link
Contributor

Choose a reason for hiding this comment

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

The logic in these three tests are almost identical. They could be combined and use something like:

      {
        config: APPLICATION_DEFAULT_CONFIG,
        input_trace: XXX,
        expected_trace: XXX
      },

This way, it's easier to maintain the shared logic and also execute all tests related to trace with a single command. It also makes it easier to add more test cases.

BTW, we should also test cases like below in combination of different config 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.

to the first suggestion, I still maintain existing way to write test because the error message for each one is different - and the reason to make error message different is: 1) group similar testcases in a single unit and 2) provide more informative error message when the test fails.

Will add other 3 testcases, and consider reorganize testcases to whatever makes sense.


verify_log_entries(1, COMPUTE_PARAMS, 'jsonPayload') do |entry|
expected_trace = \
"projects/#{d.instance.project_id}" \
Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, instead of d.instance.project_id, we could just use PROJECT, which is defined in the constants.rb file.

Copy link
Member

@igorpeshansky igorpeshansky left a comment

Choose a reason for hiding this comment

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

One more comment.

trace = record.delete(@trace_key)
entry.trace = trace if trace
if trace
Copy link
Member

Choose a reason for hiding this comment

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


verify_log_entries(1, COMPUTE_PARAMS, 'jsonPayload') do |entry|
expected_trace = \
"projects/#{d.instance.project_id}" \
Copy link
Member

Choose a reason for hiding this comment

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

I was proposing the FULL_STACKDRIVER_TRACE and NON_STACKDRIVER_TRACE, same as you... If we define one in terms of the other, we can even use FULL_STACKDRIVER_TRACE as the expected value here...

entry.trace = trace if trace
if trace
if @enable_stackdriver_trace_autoformat &&
!STACKDRIVER_TRACE_REGEXP.match(trace)
Copy link
Member

Choose a reason for hiding this comment

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

Just realized that a trace value that isn't in the right format but does have a slash will probably produce a log entry that will fail validation. If we adjust it unconditionally, then the resulting error might not make sense to the customers (e.g., "too many slashes" instead of "too few slashes"). We should confirm this behavior and, if my hunch is right, change this to a positive regexp match instead (i.e., only adjust if it has a certain form). WDYT?

Copy link
Contributor

Choose a reason for hiding this comment

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

That's a valid concern. Agreed we should confirm the behavior.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

that trace-value fail validation seems like a deal breaker - agree that if the format is not correct, autoformat should not be conducted.
Even that said, it sounds hard to setup a rule on agent side. There is no official trace-ID format available in public document I can see - so it's hard for me to set a rule to match the [TRACE-ID] part, and append prefix projects/[PROJECT-ID]/traces/ to it. Do you know who should I confirm with, and is there any service-client contract I can rely on @igorpeshansky ?

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 found format of TraceID is documented and fully supported under Trace API v1 (REST), and Trace API (rpc) - google.devtools.cloudtrace - so I will rely on that to write the regexp matching.

trace = record.delete(@trace_key)
entry.trace = trace if trace
if trace
Copy link
Contributor

Choose a reason for hiding this comment

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

Fun read. Oh Ruby... shoot me:

$ irb
2.4.3 :001 > if 0 then true else false end
 => true

entry.trace = trace if trace
if trace
if @enable_stackdriver_trace_autoformat &&
!STACKDRIVER_TRACE_REGEXP.match(trace)
Copy link
Contributor

Choose a reason for hiding this comment

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

That's a valid concern. Agreed we should confirm the behavior.

# will match the regexp is:
# "projects/my-project/traces/1234567890abcdef1234567890abcdef"
STACKDRIVER_TRACE_REGEXP = Regexp.new(
'^projects\/[^\/]*\/traces\/[^\/]*$').freeze
Copy link
Contributor

Choose a reason for hiding this comment

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

We probably wanna change the * to + in the Regexp, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

changed the way autoformat works, so we don't need to have complex regexp anymore

Copy link
Contributor Author

@StevenYCChou StevenYCChou left a comment

Choose a reason for hiding this comment

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

Updated couple things based on feedback, but not fully resolved yet.
Still need to:

  1. change implementation on regex matching part so it won't confuse user
  2. add more edge testcases @qingling128 mentioned.

@@ -393,6 +399,10 @@ module InternalConstants
config_param :monitoring_type, :string,
:default => Monitoring::PrometheusMonitoringRegistry.name

# Whether to autoformat value of "logging.googleapis.com/trace" to
# LogEntry.Trace.
config_param :enable_stackdriver_trace_autoformat, :bool, :default => true
Copy link
Contributor Author

Choose a reason for hiding this comment

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

makes sense. updated.

config: APPLICATION_DEFAULT_CONFIG
},
{
config: 'enable_stackdriver_trace_autoformat true'
Copy link
Contributor Author

Choose a reason for hiding this comment

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

added configs into constant.


verify_log_entries(1, COMPUTE_PARAMS, 'jsonPayload') do |entry|
expected_trace = \
"projects/#{d.instance.project_id}" \
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 full trace here depends on the project_id of driver. If we change the whole trace into constant, It's unclear how that project_id in full trace comes from. I think it's hiding details into constant.

I think this project_id is local to this scope under the driver here. WDYT?

end

def test_autoformat_disabled_with_stackdriver_trace_format_noncompliant_trace
config = 'enable_stackdriver_trace_autoformat false'
Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated.

@@ -338,6 +338,81 @@ def test_structured_payload_log
end
end

def test_stackdriver_trace_format_compliant_trace
full_stackdriver_trace = \
Copy link
Contributor Author

Choose a reason for hiding this comment

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

ditto - I think the full trace is project-dependent, not constant value.

d.run

verify_log_entries(1, COMPUTE_PARAMS, 'jsonPayload') do |entry|
assert_equal full_stackdriver_trace, entry['trace']
Copy link
Contributor Author

Choose a reason for hiding this comment

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

added more informative error messages.

@@ -338,6 +338,81 @@ def test_structured_payload_log
end
end

def test_stackdriver_trace_format_compliant_trace
Copy link
Contributor Author

Choose a reason for hiding this comment

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

to the first suggestion, I still maintain existing way to write test because the error message for each one is different - and the reason to make error message different is: 1) group similar testcases in a single unit and 2) provide more informative error message when the test fails.

Will add other 3 testcases, and consider reorganize testcases to whatever makes sense.

trace = record.delete(@trace_key)
entry.trace = trace if trace
if trace
if @enable_stackdriver_trace_autoformat &&
Copy link
Contributor Author

Choose a reason for hiding this comment

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

added

entry.trace = trace if trace
if trace
if @enable_stackdriver_trace_autoformat &&
!STACKDRIVER_TRACE_REGEXP.match(trace)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

that trace-value fail validation seems like a deal breaker - agree that if the format is not correct, autoformat should not be conducted.
Even that said, it sounds hard to setup a rule on agent side. There is no official trace-ID format available in public document I can see - so it's hard for me to set a rule to match the [TRACE-ID] part, and append prefix projects/[PROJECT-ID]/traces/ to it. Do you know who should I confirm with, and is there any service-client contract I can rely on @igorpeshansky ?

trace = record.delete(@trace_key)
entry.trace = trace if trace
if trace
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Contributor Author

@StevenYCChou StevenYCChou left a comment

Choose a reason for hiding this comment

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

modified the regexp expression and added more testcases.

Didn't implement the customized trace_key though, because the customized trace_key is already captured in https://github.com/GoogleCloudPlatform/fluent-plugin-google-cloud/blob/master/test/plugin/base_test.rb#L1223-L1226 .

# will match the regexp is:
# "projects/my-project/traces/1234567890abcdef1234567890abcdef"
STACKDRIVER_TRACE_REGEXP = Regexp.new(
'^projects\/[^\/]*\/traces\/[^\/]*$').freeze
Copy link
Contributor Author

Choose a reason for hiding this comment

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

changed the way autoformat works, so we don't need to have complex regexp anymore

@@ -627,7 +637,8 @@ def write(chunk)
ts_nanos)

trace = record.delete(@trace_key)
entry.trace = trace if trace
entry.trace = compute_trace(trace) if trace
Copy link
Contributor Author

Choose a reason for hiding this comment

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

as if trace is existing behavior, I won't change the logic in this PR because it's out of the original scope.

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 @qingling128 was suggesting that an empty trace should not match the regexp that causes it to be rewritten...

Copy link
Contributor

Choose a reason for hiding this comment

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

if trace is fine now since we are using positive regex match

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ack.

@@ -393,6 +398,10 @@ module InternalConstants
config_param :monitoring_type, :string,
:default => Monitoring::PrometheusMonitoringRegistry.name

# Whether to autoformat value of "logging.googleapis.com/trace" to
Copy link
Contributor

Choose a reason for hiding this comment

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

It would be nice to provide more informative description on what this configuration does to help guide users. How about:

Whether to autoformat value of "logging.googleapis.com/trace" to comply with Stackdriver Trace format ("projects/[PROJECT-ID]/traces/[TRACE-ID]") when setting the trace field of the LogEntry object.

BTW, once this is released, we can update the public documentation to add this new config.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated the comment to clarify the config!

@@ -627,7 +637,8 @@ def write(chunk)
ts_nanos)

trace = record.delete(@trace_key)
entry.trace = trace if trace
entry.trace = compute_trace(trace) if trace
Copy link
Contributor

Choose a reason for hiding this comment

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

if trace is fine now since we are using positive regex match

NO_AUTOFORMAT_STACKDRIVER_TRACE_CONFIG
]
traces = [
'',
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm... The empty string case seems to have failed the unit test for gRPC. Travis build.

It's probably due to https://github.com/GoogleCloudPlatform/fluent-plugin-google-cloud/blob/master/test/plugin/test_out_google_cloud_grpc.rb#L439.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

use the function assert_equal_with_default to be able to verify even it's an empty string ''

verify_log_entries(1, COMPUTE_PARAMS, 'jsonPayload') do |entry|
expected_trace = \
"projects/#{d.instance.project_id}/traces/#{STACKDRIVER_TRACE_ID}"
assert_equal expected_trace, entry['trace'], 'stackdriver trace ' \
Copy link
Contributor

Choose a reason for hiding this comment

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

Great message!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

thanks!

Copy link
Contributor

@qingling128 qingling128 left a comment

Choose a reason for hiding this comment

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

LGTM

sebright added a commit to sebright/microservices-demo that referenced this pull request Sep 27, 2018
This commit enables OpenCensus log correlation using
opencensus-contrib-log-correlation-log4j2
(https://github.com/census-instrumentation/opencensus-java/tree/master/contrib/log_correlation/log4j2).
The library inserts the trace ID, span ID, and sampling decision into every
Log4j log event.  This commit includes other changes to make the tracing data
available in the logs, in a format that can be interpreted by the StackDriver
Logging agent:

- Convert all adservice log statements from java.util.logging to Log4j.

- Specify a JSON format for Log4j output.  This is related to issue GoogleCloudPlatform#47.

- Add the trace ID, span ID, and sampling decision to the JSON format.  Trace
  ID and span ID use special keys that the Stackdriver Logging agent uses to
  populate the tracing data fields in the LogEntry uploaded to Stackdriver
  (https://cloud.google.com/logging/docs/agent/configuration#special_fields_in_structured_payloads).
  However, Stackdriver won't be able to link the traces and log entries until
  fluent-plugin-google-cloud can automatically format the trace ID with the
  format expected by Stackdriver
  (GoogleCloudPlatform/fluent-plugin-google-cloud#239,
  GoogleCloudPlatform/fluent-plugin-google-cloud#260).

This commit also upgrades OpenCensus to 0.16.1 in order to use
opencensus-contrib-log-correlation-log4j2.
Copy link
Member

@igorpeshansky igorpeshansky left a comment

Choose a reason for hiding this comment

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

A few more.

@@ -393,6 +398,10 @@ module InternalConstants
config_param :monitoring_type, :string,
:default => Monitoring::PrometheusMonitoringRegistry.name

# Whether to autoformat value of "logging.googleapis.com/trace" to
# LogEntry.Trace.
config_param :autoformat_stackdriver_trace, :bool, :default => true
Copy link
Member

Choose a reason for hiding this comment

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

I would suggest moving this down, after adjust_invalid_timestamps.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated

@@ -265,6 +267,14 @@ module Constants
enable_metadata_agent false
).freeze

AUTOFORMAT_STACKDRIVER_TRACE_CONFIG = %(
Copy link
Member

Choose a reason for hiding this comment

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

ENABLE_TRACE_AUTOFORMAT_CONFIG. We started this pattern with the metadata_agent configs — I think it's a bit more readable.

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 thought you recommended using imperative form for config - and my original config is called enable_stackdriver_trace_autoformat , which matches what you suggested here.

I will modify this constant to ENABLE_AUTOFORMAT_STACKDRIVER_TRACE as logging agent will format to stackdriver trace format specifically, not other trace format.

Copy link
Member

Choose a reason for hiding this comment

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

Sorry to be unclear. The names for the config constants don't necessarily have to include the full config option name — they just need to be identifiable with that option. We have this pattern elsewhere. I was suggesting that we change <FULL_NAME>_CONFIG and NO_<FULL_NAME>_CONFIG to ENABLE_<SHORT_NAME>_CONFIG and DISABLE_<SHORT_NAME>_CONFIG. Does this make sense?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

make seonse. still decide to use the ENABLE/DISABLE_FULL_NAME_CONFIG.

autoformat_stackdriver_trace true
).freeze

NO_AUTOFORMAT_STACKDRIVER_TRACE_CONFIG = %(
Copy link
Member

Choose a reason for hiding this comment

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

DISABLE_TRACE_AUTOFORMAT_CONFIG...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ditto as above


verify_log_entries(1, COMPUTE_PARAMS, 'jsonPayload') do |entry|
expected_trace = \
"projects/#{d.instance.project_id}" \
Copy link
Member

Choose a reason for hiding this comment

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

The point is that the tests should be checking complete expected values. If you expect the resulting trace to have a particular project id, the constant should have that. I was suggesting defining the FULL_STACKDRIVER_TRACE as:

NON_STACKDRIVER_TRACE = "1234567890abcdef1234567890abcdef".freeze
FULL_STACKDRIVER_TRACE = "projects/#{PROJECT_ID}/traces/#{NON_STACKDRIVER_TRACE}".freeze

in constants.rb.

"projects/#{PROJECT_ID}/traces/",
"projects/#{PROJECT_ID}/traces/#{NON_STACKDRIVER_TRACE_ID}",
"projects//traces/#{STACKDRIVER_TRACE_ID}",
TRACE # full trace won't be modified either
Copy link
Member

Choose a reason for hiding this comment

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

Nit: missing trailing ..

"projects//traces/#{STACKDRIVER_TRACE_ID}",
TRACE # full trace won't be modified either
]
configs.product(traces).collect do |config, trace|
Copy link
Member

Choose a reason for hiding this comment

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

You're throwing away the collect result, so I'd use each instead.

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 - thanks for catching it!

@@ -338,6 +338,98 @@ def test_structured_payload_log
end
end

def test_autoformat_enabled_with_stackdriver_trace_id_as_trace
configs = [
Copy link
Member

Choose a reason for hiding this comment

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

I wouldn't bother with just the configs local variable — just use the array literal. Also below.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

I meant:

    [
      APPLICATION_DEFAULT_CONFIG,
      AUTOFORMAT_STACKDRIVER_TRACE_CONFIG
      ENABLE_AUTOFORMAT_STACKDRIVER_TRACE_CONFIG
    ].each do |config|
      ...
    end

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated - to make it consistent with rest of the tests if there is only single list to iterate through.

verify_log_entries(1, COMPUTE_PARAMS, 'jsonPayload') do |entry|
assert_equal trace, entry['trace'], 'trace as non stackdriver' \
'trace id should not be autoformatted with ' \
"config #{config}."
Copy link
Member

Choose a reason for hiding this comment

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

Indentation.

verify_log_entries(1, COMPUTE_PARAMS, 'jsonPayload') do |entry|
expected_trace = \
"projects/#{d.instance.project_id}/traces/#{STACKDRIVER_TRACE_ID}"
assert_equal expected_trace, entry['trace'], 'stackdriver trace ' \
Copy link
Member

Choose a reason for hiding this comment

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

Want to start the message on the next line? That way it's obvious that it's a separate entity...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

modified!

"projects/#{d.instance.project_id}/traces/#{STACKDRIVER_TRACE_ID}"
assert_equal expected_trace, entry['trace'], 'stackdriver trace ' \
'id should be autoformatted with config ' \
"#{test_config}."
Copy link
Member

Choose a reason for hiding this comment

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

I would just say "should be autoformatted when autoformat_stackdriver_trace is enabled", rather than print the config (which could at some point become larger than that). Also note that APPLICATION_DEFAULT_CONFIG is empty, so it'd be confusing to see "with config ." in the output.

Copy link
Member

Choose a reason for hiding this comment

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

Ping?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated - sorry miss this part in the previous change.

Copy link
Member

Choose a reason for hiding this comment

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

Can we do the same in test_non_stackdriver_trace_id_compliant_trace_with_any_autoformat_config as well? I don't think we have any other tests that interpolate the full config in the message...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated

sebright added a commit to sebright/microservices-demo that referenced this pull request Sep 28, 2018
This commit enables OpenCensus log correlation using
opencensus-contrib-log-correlation-log4j2
(https://github.com/census-instrumentation/opencensus-java/tree/master/contrib/log_correlation/log4j2).
The library inserts the trace ID, span ID, and sampling decision into every
Log4j log event.  This commit includes other changes to make the tracing data
available in the logs, in a format that can be interpreted by the Stackdriver
Logging agent:

- Convert all adservice log statements from java.util.logging to Log4j.

- Specify a JSON format for Log4j output.  This is related to issue GoogleCloudPlatform#47.

- Add the trace ID, span ID, and sampling decision to the JSON format.  Trace
  ID and span ID use special keys that the Stackdriver Logging agent uses to
  populate the tracing data fields in the LogEntry uploaded to Stackdriver
  (https://cloud.google.com/logging/docs/agent/configuration#special_fields_in_structured_payloads).
  However, Stackdriver won't be able to link the traces and log entries until
  fluent-plugin-google-cloud can automatically format the trace ID with the
  format expected by Stackdriver
  (GoogleCloudPlatform/fluent-plugin-google-cloud#239,
  GoogleCloudPlatform/fluent-plugin-google-cloud#260).

This commit also upgrades OpenCensus to 0.16.1 in order to use
opencensus-contrib-log-correlation-log4j2.
Copy link
Member

@igorpeshansky igorpeshansky left a comment

Choose a reason for hiding this comment

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

Mostly replying to your comments and pinging the ones you didn't respond to.

@@ -338,6 +338,98 @@ def test_structured_payload_log
end
end

def test_autoformat_enabled_with_stackdriver_trace_id_as_trace
configs = [
Copy link
Member

Choose a reason for hiding this comment

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

I meant:

    [
      APPLICATION_DEFAULT_CONFIG,
      AUTOFORMAT_STACKDRIVER_TRACE_CONFIG
      ENABLE_AUTOFORMAT_STACKDRIVER_TRACE_CONFIG
    ].each do |config|
      ...
    end

@@ -265,6 +267,14 @@ module Constants
enable_metadata_agent false
).freeze

AUTOFORMAT_STACKDRIVER_TRACE_CONFIG = %(
Copy link
Member

Choose a reason for hiding this comment

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

Sorry to be unclear. The names for the config constants don't necessarily have to include the full config option name — they just need to be identifiable with that option. We have this pattern elsewhere. I was suggesting that we change <FULL_NAME>_CONFIG and NO_<FULL_NAME>_CONFIG to ENABLE_<SHORT_NAME>_CONFIG and DISABLE_<SHORT_NAME>_CONFIG. Does this make sense?

@@ -338,6 +338,81 @@ def test_structured_payload_log
end
end

def test_stackdriver_trace_format_compliant_trace
full_stackdriver_trace = \
Copy link
Member

Choose a reason for hiding this comment

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

The project we feed into the tests is a constant, though... So we could construct the full expected value as a constant.

@@ -676,6 +686,14 @@ def write(chunk)

private

def compute_trace(trace)
if @autoformat_stackdriver_trace &&
Copy link
Member

Choose a reason for hiding this comment

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

The point here is that the important bit is the early return, not the clause. A reader, seeing return trace unless [...] will think: "Ah, this function will return one of two values — an untransformed one unless some condition holds true, and a transformed one otherwise". Then they can dig into the condition. In the code you're proposing, the logic goes the other way — the reader first has to get through a large condition to figure out how the value is transformed, and then look at the end of the function to see that it's returned.

Incidentally, even if we agree that your current structure is more readable, I think it's better to say return "projects/#{@project_id}/traces/#{trace}" instead of assigning it back to a parameter trace only to return it in the end.

d.run
verify_log_entries(1, COMPUTE_PARAMS, 'jsonPayload') do |entry|
expected_trace = \
"projects/#{d.instance.project_id}/traces/#{STACKDRIVER_TRACE_ID}"
Copy link
Member

Choose a reason for hiding this comment

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

The interpolation happens before the freeze, so the resulting string is a constant. Plus, this would be consistent with the rest of the testing code.

"projects/#{d.instance.project_id}/traces/#{STACKDRIVER_TRACE_ID}"
assert_equal expected_trace, entry['trace'], 'stackdriver trace ' \
'id should be autoformatted with config ' \
"#{test_config}."
Copy link
Member

Choose a reason for hiding this comment

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

Ping?

"projects/#{d.instance.project_id}/traces/#{STACKDRIVER_TRACE_ID}"
assert_equal expected_trace, entry['trace'], 'stackdriver trace ' \
'id should be autoformatted with config ' \
"#{test_config}."
Copy link
Member

Choose a reason for hiding this comment

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

Can we do the same in test_non_stackdriver_trace_id_compliant_trace_with_any_autoformat_config as well? I don't think we have any other tests that interpolate the full config in the message...

Copy link
Member

@igorpeshansky igorpeshansky left a comment

Choose a reason for hiding this comment

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

One comment.

"projects/#{PROJECT_ID}/traces/#{STACKDRIVER_TRACE_ID}".freeze

# Invalid trace id for stackdriver.
EMPTY_STRING = ''.freeze
Copy link
Member

Choose a reason for hiding this comment

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

Personally, I think this one is overkill, but I'll let @qingling128 make this call.

Copy link
Contributor

Choose a reason for hiding this comment

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

Haha, i'm fine with defining an empty string constant. It could be shared by others as well though, not necessarily Invalid trace id for stackdriver.

Copy link
Member

@igorpeshansky igorpeshansky left a comment

Choose a reason for hiding this comment

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

LGTM :shipit:

@StevenYCChou StevenYCChou merged commit b5a4a2a into master Sep 29, 2018
@igorpeshansky igorpeshansky deleted the ycchou-stackdriver-trace-autoformat branch September 29, 2018 13:07
ahmetb pushed a commit to GoogleCloudPlatform/microservices-demo that referenced this pull request Oct 2, 2018
)

This commit enables OpenCensus log correlation using
opencensus-contrib-log-correlation-log4j2
(https://github.com/census-instrumentation/opencensus-java/tree/master/contrib/log_correlation/log4j2).
The library inserts the trace ID, span ID, and sampling decision into every
Log4j log event.  This commit includes other changes to make the tracing data
available in the logs, in a format that can be interpreted by the Stackdriver
Logging agent:

- Convert all adservice log statements from java.util.logging to Log4j.

- Specify a JSON format for Log4j output.  This is related to issue #47.

- Add the trace ID, span ID, and sampling decision to the JSON format.  Trace
  ID and span ID use special keys that the Stackdriver Logging agent uses to
  populate the tracing data fields in the LogEntry uploaded to Stackdriver
  (https://cloud.google.com/logging/docs/agent/configuration#special_fields_in_structured_payloads).
  However, Stackdriver won't be able to link the traces and log entries until
  fluent-plugin-google-cloud can automatically format the trace ID with the
  format expected by Stackdriver
  (GoogleCloudPlatform/fluent-plugin-google-cloud#239,
  GoogleCloudPlatform/fluent-plugin-google-cloud#260).

This commit also upgrades OpenCensus to 0.16.1 in order to use
opencensus-contrib-log-correlation-log4j2.
sebright added a commit to sebright/microservices-demo that referenced this pull request Oct 2, 2018
This change is necessary for log correlation to work before
GoogleCloudPlatform/fluent-plugin-google-cloud#260 is
available.
sebright added a commit to sebright/opencensus-experiments that referenced this pull request Oct 25, 2018
…nfig.

Formatting the trace ID in the logging configuration is no longer necessary now
that fluent-plugin-google-cloud formats the trace ID
(GoogleCloudPlatform/fluent-plugin-google-cloud#260).
sebright added a commit to census-ecosystem/opencensus-experiments that referenced this pull request Oct 30, 2018
…nfig. (#68)

Formatting the trace ID in the logging configuration is no longer necessary now
that fluent-plugin-google-cloud formats the trace ID
(GoogleCloudPlatform/fluent-plugin-google-cloud#260).
rghetia pushed a commit to census-ecosystem/opencensus-experiments that referenced this pull request Dec 12, 2018
…nfig. (#68)

Formatting the trace ID in the logging configuration is no longer necessary now
that fluent-plugin-google-cloud formats the trace ID
(GoogleCloudPlatform/fluent-plugin-google-cloud#260).
neptune-web added a commit to neptune-web/kubernetes-microservices-sam that referenced this pull request Jun 12, 2022
…#59)

This commit enables OpenCensus log correlation using
opencensus-contrib-log-correlation-log4j2
(https://github.com/census-instrumentation/opencensus-java/tree/master/contrib/log_correlation/log4j2).
The library inserts the trace ID, span ID, and sampling decision into every
Log4j log event.  This commit includes other changes to make the tracing data
available in the logs, in a format that can be interpreted by the Stackdriver
Logging agent:

- Convert all adservice log statements from java.util.logging to Log4j.

- Specify a JSON format for Log4j output.  This is related to issue #47.

- Add the trace ID, span ID, and sampling decision to the JSON format.  Trace
  ID and span ID use special keys that the Stackdriver Logging agent uses to
  populate the tracing data fields in the LogEntry uploaded to Stackdriver
  (https://cloud.google.com/logging/docs/agent/configuration#special_fields_in_structured_payloads).
  However, Stackdriver won't be able to link the traces and log entries until
  fluent-plugin-google-cloud can automatically format the trace ID with the
  format expected by Stackdriver
  (GoogleCloudPlatform/fluent-plugin-google-cloud#239,
  GoogleCloudPlatform/fluent-plugin-google-cloud#260).

This commit also upgrades OpenCensus to 0.16.1 in order to use
opencensus-contrib-log-correlation-log4j2.
oplik0 pushed a commit to oplik0/bso that referenced this pull request Jun 6, 2024
…#59)

This commit enables OpenCensus log correlation using
opencensus-contrib-log-correlation-log4j2
(https://github.com/census-instrumentation/opencensus-java/tree/master/contrib/log_correlation/log4j2).
The library inserts the trace ID, span ID, and sampling decision into every
Log4j log event.  This commit includes other changes to make the tracing data
available in the logs, in a format that can be interpreted by the Stackdriver
Logging agent:

- Convert all adservice log statements from java.util.logging to Log4j.

- Specify a JSON format for Log4j output.  This is related to issue #47.

- Add the trace ID, span ID, and sampling decision to the JSON format.  Trace
  ID and span ID use special keys that the Stackdriver Logging agent uses to
  populate the tracing data fields in the LogEntry uploaded to Stackdriver
  (https://cloud.google.com/logging/docs/agent/configuration#special_fields_in_structured_payloads).
  However, Stackdriver won't be able to link the traces and log entries until
  fluent-plugin-google-cloud can automatically format the trace ID with the
  format expected by Stackdriver
  (GoogleCloudPlatform/fluent-plugin-google-cloud#239,
  GoogleCloudPlatform/fluent-plugin-google-cloud#260).

This commit also upgrades OpenCensus to 0.16.1 in order to use
opencensus-contrib-log-correlation-log4j2.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants