Skip to content

Commit

Permalink
Merge pull request #224 from dynatrace-oss-contrib/feat/jinja-whitesp…
Browse files Browse the repository at this point in the history
…ace-control
  • Loading branch information
lquerel authored Jul 2, 2024
2 parents 98fe349 + ac94ee8 commit 502c5f3
Show file tree
Hide file tree
Showing 8 changed files with 223 additions and 13 deletions.
14 changes: 8 additions & 6 deletions crates/weaver_forge/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ templates/
html/ <-- Templates to generate the semantic conventions in HTML
...
markdown/ <-- Templates to generate the semantic conventions in markdown
...
...
rust/ <-- Templates to generate the semantic conventions in Rust
...
...
go/ <-- Templates to generate the semantic conventions in Go
...
schema/
Expand Down Expand Up @@ -78,6 +78,7 @@ documentation for more details.
## Global Variables

All templates have access to the following global variables:

- `ctx`: The context object that contains the resolved registry or the output of
the JQ filter if defined in the `weaver.yaml` configuration file.
- `params`: The parameters defined in the `weaver.yaml` configuration file or overridden
Expand Down Expand Up @@ -130,12 +131,13 @@ Jinja templates can also access the parameters:
## Jinja Filters

All the filters available in the MiniJinja template engine are available (see
this online [documentation](https://docs.rs/minijinja/latest/minijinja/filters/index.html)).
this online [documentation](https://docs.rs/minijinja/latest/minijinja/filters/index.html)).

In addition, OTel Weaver provides a set of custom filters to facilitate the
generation of documentation and code.

The following filters are available:

- `lower_case`: Converts a string to lowercase.
- `upper_case`: Converts a string to UPPERCASE.
- `title_case`: Converts a string to TitleCase.
Expand All @@ -146,7 +148,7 @@ The following filters are available:
- `kebab_case`: Converts a string to kebab-case.
- `screaming_kebab_case`: Converts a string to SCREAMING-KEBAB-CASE.
- `capitalize_first`: Capitalizes the first letter of a string.
- `kebab_case_const`: Generates kebab-case constants which follow semantic convention namespacing rules (underscores are ignored, but . is meaningful).
- `kebab_case_const`: Generates kebab-case constants which follow semantic convention namespacing rules (underscores are ignored, but . is meaningful).
- `pascal_case_const`: Generates PascalCase constants which follow semantic convention namespacing rules (underscores are ignored, but . is meaningful).
- `camel_case_const`: Generates camelCase constants which follow semantic convention namespacing rules (underscores are ignored, but . is meaningful).
- `snake_case_const`: Generates snake_case constants which follow semantic convention namespacing rules (underscores are ignored, but . is meaningful).
Expand All @@ -165,7 +167,7 @@ e.g. \[\[a,b\],\[c\]\] => \[a,b,c\]
- `attribute_namespace`: Converts {namespace}.{attribute_id} to {namespace}.
- `required`: Filters a list of `Attribute`s to include only the required attributes. The "conditionally_required" attributes are not returned by this filter.
- `not_required`: Filters a list of `Attribute`s to only include non-required attributes. The "conditionally_required" attributes are returned by this filter.
- `instantiated_type`: Filters a type to return the instantiated type.
- `instantiated_type`: Filters a type to return the instantiated type.
- `enum_type`: Filters a type to return the enum type or an error if the type is not an enum.
- `markdown_to_html`: Converts a markdown string to an HTML string.
- `map_text`: Converts an input into a string based on the `text_maps` section of the `weaver.yaml` configuration file
Expand Down Expand Up @@ -212,7 +214,7 @@ value if the name of the text map or the input are not found in the `text_maps`
## Jinja Functions

All the functions available in the MiniJinja template engine are available (see
All the functions available in the MiniJinja template engine are available (see
this online [documentation](https://docs.rs/minijinja/latest/minijinja/functions/index.html)).

Right now, OTel Weaver does not provide any custom functions but feel free to
Expand Down
17 changes: 17 additions & 0 deletions crates/weaver_forge/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ pub(crate) struct TargetConfig {
/// Configuration for the template syntax.
#[serde(default)]
pub(crate) template_syntax: TemplateSyntax,
/// Configuration for the whitespace behavior on the template engine.
#[serde(default)]
pub(crate) whitespace_control: WhitespaceControl,

/// Parameters for the templates.
/// These parameters can be overridden by parameters passed to the CLI.
Expand Down Expand Up @@ -298,6 +301,20 @@ impl Default for TemplateSyntax {
}
}

/// Whitespace control configuration for the template engine.
#[derive(Deserialize, Debug, Clone, Default)]
pub struct WhitespaceControl {
/// Configures the behavior of the first newline after a block.
/// See <https://docs.rs/minijinja/latest/minijinja/struct.Environment.html#method.set_trim_blocks>
pub trim_blocks: bool,
/// Configures the behavior of leading spaces and tabs from the start of a line to a block.
/// See <https://docs.rs/minijinja/latest/minijinja/struct.Environment.html#method.set_lstrip_blocks>
pub lstrip_blocks: bool,
/// Configures whether trailing newline are preserved when rendering templates.
/// See <https://docs.rs/minijinja/latest/minijinja/struct.Environment.html#method.set_keep_trailing_newline>
pub keep_trailing_newline: bool,
}

impl Default for CaseConvention {
/// Default case convention is PascalCase
fn default() -> Self {
Expand Down
51 changes: 51 additions & 0 deletions crates/weaver_forge/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,13 @@ impl TemplateEngine {
});
env.set_syntax(syntax);

// Jinja whitespace control
// https://docs.rs/minijinja/latest/minijinja/syntax/index.html#whitespace-control
let whitespace_control = self.target_config.whitespace_control.clone();
env.set_trim_blocks(whitespace_control.trim_blocks);
env.set_lstrip_blocks(whitespace_control.lstrip_blocks);
env.set_keep_trailing_newline(whitespace_control.keep_trailing_newline);

code::add_filters(&mut env, &self.target_config);
ansi::add_filters(&mut env);
case::add_filters(&mut env, &self.target_config);
Expand Down Expand Up @@ -682,4 +689,48 @@ mod tests {

assert!(diff_dir("expected_output", "observed_output").unwrap());
}

#[test]
fn test_whitespace_control() {
let logger = TestLogger::default();
let loader = FileSystemFileLoader::try_new("whitespace_control_templates".into(), "test")
.expect("Failed to create file system loader");
let engine = super::TemplateEngine::try_new(loader, Params::default())
.expect("Failed to create template engine");

let registry_id = "default";
let mut registry = SemConvRegistry::try_from_path_pattern(registry_id, "data/*.yaml")
.expect("Failed to load registry");
let schema = SchemaResolver::resolve_semantic_convention_registry(&mut registry)
.expect("Failed to resolve registry");

let template_registry = ResolvedRegistry::try_from_resolved_registry(
schema.registry(registry_id).expect("registry not found"),
schema.catalog(),
)
.unwrap_or_else(|e| {
panic!(
"Failed to create the context for the template evaluation: {:?}",
e
)
});

engine
.generate(
logger.clone(),
&template_registry,
Path::new("whitespace_control_templates/test/observed_output"),
&OutputDirective::File,
)
.inspect_err(|e| {
print_dedup_errors(logger.clone(), e.clone());
})
.expect("Failed to generate registry assets");

assert!(diff_dir(
"whitespace_control_templates/test/expected_output",
"whitespace_control_templates/test/observed_output"
)
.unwrap());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Semantic Convention Registry

Url:

## Attribute Groups

- [attributes.jvm.memory](attribute_group/attributes_jvm_memory.md)
- [registry.db](attribute_group/registry_db.md)
- [registry.http](attribute_group/registry_http.md)
- [registry.network](attribute_group/registry_network.md)
- [server](attribute_group/server.md)
- [registry.url](attribute_group/registry_url.md)
- [registry.user_agent](attribute_group/registry_user_agent.md)

## Events

- [ios.lifecycle.events](event/ios_lifecycle_events.md)
- [android.lifecycle.events](event/android_lifecycle_events.md)

## Metrics

- [metric.jvm.memory.used](metric/metric_jvm_memory_used.md)
- [metric.jvm.memory.committed](metric/metric_jvm_memory_committed.md)
- [metric.jvm.memory.limit](metric/metric_jvm_memory_limit.md)
- [metric.jvm.memory.used_after_last_gc](metric/metric_jvm_memory_used_after_last_gc.md)
- [metric.jvm.gc.duration](metric/metric_jvm_gc_duration.md)
- [metric.jvm.thread.count](metric/metric_jvm_thread_count.md)
- [metric.jvm.class.loaded](metric/metric_jvm_class_loaded.md)
- [metric.jvm.class.unloaded](metric/metric_jvm_class_unloaded.md)
- [metric.jvm.class.count](metric/metric_jvm_class_count.md)
- [metric.jvm.cpu.count](metric/metric_jvm_cpu_count.md)
- [metric.jvm.cpu.time](metric/metric_jvm_cpu_time.md)
- [metric.jvm.cpu.recent_utilization](metric/metric_jvm_cpu_recent_utilization.md)

## Metric Groups

## Resource

- [otel.scope](resource/otel_scope.md)
- [otel.library](resource/otel_library.md)

## Scope

## Span

- [db](span/db.md)
- [db.mssql](span/db_mssql.md)
- [db.cassandra](span/db_cassandra.md)
- [db.hbase](span/db_hbase.md)
- [db.couchdb](span/db_couchdb.md)
- [db.redis](span/db_redis.md)
- [db.mongodb](span/db_mongodb.md)
- [db.elasticsearch](span/db_elasticsearch.md)
- [db.sql](span/db_sql.md)
- [db.cosmosdb](span/db_cosmosdb.md)
- [db.tech](span/db_tech.md)
57 changes: 57 additions & 0 deletions crates/weaver_forge/whitespace_control_templates/test/registry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Semantic Convention Registry

Url:{{ registry_url }}

## Attribute Groups

{% for group in ctx.groups %}
{% if group.type == "attribute_group" %}
- [{{ group.id }}](attribute_group/{{ group.id | file_name }}.md)
{% endif %}
{% endfor %}

## Events

{% for group in ctx.groups %}
{% if group.type == "event" %}
- [{{ group.id }}](event/{{ group.id | file_name }}.md)
{% endif %}
{% endfor %}

## Metrics

{% for group in ctx.groups %}
{% if group.type == "metric" %}
- [{{ group.id }}](metric/{{ group.id | file_name }}.md)
{% endif %}
{% endfor %}

## Metric Groups
{% for group in ctx.groups %}
{% if group.type == "metric_group" %}
- [{{ group.id }}](metric_group/{{ group.id | file_name }}.md)
{% endif %}
{% endfor %}

## Resource

{% for group in ctx.groups %}
{% if group.type == "resource" %}
- [{{ group.id }}](resource/{{ group.id | file_name }}.md)
{% endif %}
{% endfor %}

## Scope
{% for group in ctx.groups %}
{% if group.type == "scope" %}
- [{{ group.id }}](scope/{{ group.id | file_name }}.md)
{% endif %}
{% endfor %}

## Span

{% for group in ctx.groups %}
{% if group.type == "span" %}
- [{{ group.id }}](span/{{ group.id | file_name }}.md)
{% endif %}
{% endfor %}
22 changes: 22 additions & 0 deletions crates/weaver_forge/whitespace_control_templates/test/weaver.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
file_name: snake_case
function_name: PascalCase
arg_name: camelCase
struct_name: PascalCase
field_name: PascalCase

type_mapping:
int: int64
double: double
boolean: bool
string: string
"int[]": "[]int64"
"double[]": "[]double"
"boolean[]": "[]bool"
"string[]": "[]string"

acronyms: ["iOS", "API", "URL"]

whitespace_control:
trim_blocks: true
lstrip_blocks: true
keep_trailing_newline: true
5 changes: 1 addition & 4 deletions crates/weaver_semconv/src/semconv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,10 +302,7 @@ mod tests {
let semconv_url = "http://unknown.com/unknown-semconv.yaml";
let semconv_spec = SemConvSpec::from_url(semconv_url);
assert!(semconv_spec.is_err());
assert!(matches!(
semconv_spec.unwrap_err(),
InvalidSemConvSpec { .. }
));
assert!(matches!(semconv_spec.unwrap_err(), RegistryNotFound { .. }));
}

#[test]
Expand Down
14 changes: 11 additions & 3 deletions docs/weaver-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ following options:
# double: doubleKey
# boolean: booleanKey
# string: stringKey

# Deprecated, please use text_maps instead
# Configuration of the type mapping. This is useful to generate code in a
# specific language. This is optional.
Expand All @@ -33,7 +33,8 @@ following options:
# "string[]": "[]string"
# ...

# Uncomment this section to specify the configuration of the Jinja template syntax.
# Uncomment this section to specify the configuration of the Jinja template syntax
# and control whitespace behavior.
# Note: The default syntax is strongly recommended.
#template_syntax:
# block_start: "{%"
Expand All @@ -43,6 +44,13 @@ following options:
# comment_start: "{#"
# comment_end: "#}"

# Uncomment this section to specify the whitespace behavior of the Jinja template engine.
# For more info, see: https://docs.rs/minijinja/latest/minijinja/syntax/index.html#whitespace-control
# whitespace_control:
# trim_blocks: true
# lstrip_blocks: true
# keep_trailing_newline: true

# Uncomment the following section to specify a list of acronyms that
# will be interpreted by the acronym filter. This is optional.
# acronyms: ["iOS", "HTTP", "API", "SDK", "CLI", "URL", "JSON", "XML", "HTML"]
Expand All @@ -52,7 +60,7 @@ following options:
# params:
# param1: val1
# param2: val2

# Uncomment the following templates to override the default template
# mapping. Each template mapping specifies a jaq filter (compatible with jq)
# to apply to every file matching the pattern. The application_mode specifies
Expand Down

0 comments on commit 502c5f3

Please sign in to comment.