AWS SDK

AWS SDK

rev. fe50a9dd499faa70ec4be9ad3bcc43bd13785b4c

Files changed:

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-observability-otel/Cargo.toml

@@ -0,1 +0,32 @@
           1  +
# Code generated by software.amazon.smithy.rust.codegen.smithy-rs. DO NOT EDIT.
           2  +
[package]
           3  +
name = "aws-smithy-observability-otel"
           4  +
version = "0.1.0"
           5  +
authors = ["AWS Rust SDK Team <aws-sdk-rust@amazon.com>"]
           6  +
description = "Smithy OpenTelemetry observability implementation."
           7  +
edition = "2021"
           8  +
license = "Apache-2.0"
           9  +
repository = "https://github.com/awslabs/smithy-rs"
          10  +
[package.metadata.docs.rs]
          11  +
all-features = true
          12  +
targets = ["x86_64-unknown-linux-gnu"]
          13  +
cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"]
          14  +
rustdoc-args = ["--cfg", "docsrs"]
          15  +
          16  +
[dependencies]
          17  +
value-bag = "1.10.0"
          18  +
async-global-executor = "2.4.1"
          19  +
async-task = "=4.7.1"
          20  +
          21  +
[dependencies.aws-smithy-observability]
          22  +
path = "../aws-smithy-observability"
          23  +
version = "0.1.0"
          24  +
          25  +
[dependencies.opentelemetry]
          26  +
version = "0.26.0"
          27  +
features = ["metrics"]
          28  +
[target."cfg(not(target_arch = \"powerpc\"))".dependencies.opentelemetry_sdk]
          29  +
version = "0.26.0"
          30  +
features = ["metrics", "testing"]
          31  +
[dev-dependencies.tokio]
          32  +
version = "1.23.1"

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-observability-otel/LICENSE

@@ -0,1 +0,175 @@
           1  +
           2  +
                                 Apache License
           3  +
                           Version 2.0, January 2004
           4  +
                        http://www.apache.org/licenses/
           5  +
           6  +
   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
           7  +
           8  +
   1. Definitions.
           9  +
          10  +
      "License" shall mean the terms and conditions for use, reproduction,
          11  +
      and distribution as defined by Sections 1 through 9 of this document.
          12  +
          13  +
      "Licensor" shall mean the copyright owner or entity authorized by
          14  +
      the copyright owner that is granting the License.
          15  +
          16  +
      "Legal Entity" shall mean the union of the acting entity and all
          17  +
      other entities that control, are controlled by, or are under common
          18  +
      control with that entity. For the purposes of this definition,
          19  +
      "control" means (i) the power, direct or indirect, to cause the
          20  +
      direction or management of such entity, whether by contract or
          21  +
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
          22  +
      outstanding shares, or (iii) beneficial ownership of such entity.
          23  +
          24  +
      "You" (or "Your") shall mean an individual or Legal Entity
          25  +
      exercising permissions granted by this License.
          26  +
          27  +
      "Source" form shall mean the preferred form for making modifications,
          28  +
      including but not limited to software source code, documentation
          29  +
      source, and configuration files.
          30  +
          31  +
      "Object" form shall mean any form resulting from mechanical
          32  +
      transformation or translation of a Source form, including but
          33  +
      not limited to compiled object code, generated documentation,
          34  +
      and conversions to other media types.
          35  +
          36  +
      "Work" shall mean the work of authorship, whether in Source or
          37  +
      Object form, made available under the License, as indicated by a
          38  +
      copyright notice that is included in or attached to the work
          39  +
      (an example is provided in the Appendix below).
          40  +
          41  +
      "Derivative Works" shall mean any work, whether in Source or Object
          42  +
      form, that is based on (or derived from) the Work and for which the
          43  +
      editorial revisions, annotations, elaborations, or other modifications
          44  +
      represent, as a whole, an original work of authorship. For the purposes
          45  +
      of this License, Derivative Works shall not include works that remain
          46  +
      separable from, or merely link (or bind by name) to the interfaces of,
          47  +
      the Work and Derivative Works thereof.
          48  +
          49  +
      "Contribution" shall mean any work of authorship, including
          50  +
      the original version of the Work and any modifications or additions
          51  +
      to that Work or Derivative Works thereof, that is intentionally
          52  +
      submitted to Licensor for inclusion in the Work by the copyright owner
          53  +
      or by an individual or Legal Entity authorized to submit on behalf of
          54  +
      the copyright owner. For the purposes of this definition, "submitted"
          55  +
      means any form of electronic, verbal, or written communication sent
          56  +
      to the Licensor or its representatives, including but not limited to
          57  +
      communication on electronic mailing lists, source code control systems,
          58  +
      and issue tracking systems that are managed by, or on behalf of, the
          59  +
      Licensor for the purpose of discussing and improving the Work, but
          60  +
      excluding communication that is conspicuously marked or otherwise
          61  +
      designated in writing by the copyright owner as "Not a Contribution."
          62  +
          63  +
      "Contributor" shall mean Licensor and any individual or Legal Entity
          64  +
      on behalf of whom a Contribution has been received by Licensor and
          65  +
      subsequently incorporated within the Work.
          66  +
          67  +
   2. Grant of Copyright License. Subject to the terms and conditions of
          68  +
      this License, each Contributor hereby grants to You a perpetual,
          69  +
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
          70  +
      copyright license to reproduce, prepare Derivative Works of,
          71  +
      publicly display, publicly perform, sublicense, and distribute the
          72  +
      Work and such Derivative Works in Source or Object form.
          73  +
          74  +
   3. Grant of Patent License. Subject to the terms and conditions of
          75  +
      this License, each Contributor hereby grants to You a perpetual,
          76  +
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
          77  +
      (except as stated in this section) patent license to make, have made,
          78  +
      use, offer to sell, sell, import, and otherwise transfer the Work,
          79  +
      where such license applies only to those patent claims licensable
          80  +
      by such Contributor that are necessarily infringed by their
          81  +
      Contribution(s) alone or by combination of their Contribution(s)
          82  +
      with the Work to which such Contribution(s) was submitted. If You
          83  +
      institute patent litigation against any entity (including a
          84  +
      cross-claim or counterclaim in a lawsuit) alleging that the Work
          85  +
      or a Contribution incorporated within the Work constitutes direct
          86  +
      or contributory patent infringement, then any patent licenses
          87  +
      granted to You under this License for that Work shall terminate
          88  +
      as of the date such litigation is filed.
          89  +
          90  +
   4. Redistribution. You may reproduce and distribute copies of the
          91  +
      Work or Derivative Works thereof in any medium, with or without
          92  +
      modifications, and in Source or Object form, provided that You
          93  +
      meet the following conditions:
          94  +
          95  +
      (a) You must give any other recipients of the Work or
          96  +
          Derivative Works a copy of this License; and
          97  +
          98  +
      (b) You must cause any modified files to carry prominent notices
          99  +
          stating that You changed the files; and
         100  +
         101  +
      (c) You must retain, in the Source form of any Derivative Works
         102  +
          that You distribute, all copyright, patent, trademark, and
         103  +
          attribution notices from the Source form of the Work,
         104  +
          excluding those notices that do not pertain to any part of
         105  +
          the Derivative Works; and
         106  +
         107  +
      (d) If the Work includes a "NOTICE" text file as part of its
         108  +
          distribution, then any Derivative Works that You distribute must
         109  +
          include a readable copy of the attribution notices contained
         110  +
          within such NOTICE file, excluding those notices that do not
         111  +
          pertain to any part of the Derivative Works, in at least one
         112  +
          of the following places: within a NOTICE text file distributed
         113  +
          as part of the Derivative Works; within the Source form or
         114  +
          documentation, if provided along with the Derivative Works; or,
         115  +
          within a display generated by the Derivative Works, if and
         116  +
          wherever such third-party notices normally appear. The contents
         117  +
          of the NOTICE file are for informational purposes only and
         118  +
          do not modify the License. You may add Your own attribution
         119  +
          notices within Derivative Works that You distribute, alongside
         120  +
          or as an addendum to the NOTICE text from the Work, provided
         121  +
          that such additional attribution notices cannot be construed
         122  +
          as modifying the License.
         123  +
         124  +
      You may add Your own copyright statement to Your modifications and
         125  +
      may provide additional or different license terms and conditions
         126  +
      for use, reproduction, or distribution of Your modifications, or
         127  +
      for any such Derivative Works as a whole, provided Your use,
         128  +
      reproduction, and distribution of the Work otherwise complies with
         129  +
      the conditions stated in this License.
         130  +
         131  +
   5. Submission of Contributions. Unless You explicitly state otherwise,
         132  +
      any Contribution intentionally submitted for inclusion in the Work
         133  +
      by You to the Licensor shall be under the terms and conditions of
         134  +
      this License, without any additional terms or conditions.
         135  +
      Notwithstanding the above, nothing herein shall supersede or modify
         136  +
      the terms of any separate license agreement you may have executed
         137  +
      with Licensor regarding such Contributions.
         138  +
         139  +
   6. Trademarks. This License does not grant permission to use the trade
         140  +
      names, trademarks, service marks, or product names of the Licensor,
         141  +
      except as required for reasonable and customary use in describing the
         142  +
      origin of the Work and reproducing the content of the NOTICE file.
         143  +
         144  +
   7. Disclaimer of Warranty. Unless required by applicable law or
         145  +
      agreed to in writing, Licensor provides the Work (and each
         146  +
      Contributor provides its Contributions) on an "AS IS" BASIS,
         147  +
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
         148  +
      implied, including, without limitation, any warranties or conditions
         149  +
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
         150  +
      PARTICULAR PURPOSE. You are solely responsible for determining the
         151  +
      appropriateness of using or redistributing the Work and assume any
         152  +
      risks associated with Your exercise of permissions under this License.
         153  +
         154  +
   8. Limitation of Liability. In no event and under no legal theory,
         155  +
      whether in tort (including negligence), contract, or otherwise,
         156  +
      unless required by applicable law (such as deliberate and grossly
         157  +
      negligent acts) or agreed to in writing, shall any Contributor be
         158  +
      liable to You for damages, including any direct, indirect, special,
         159  +
      incidental, or consequential damages of any character arising as a
         160  +
      result of this License or out of the use or inability to use the
         161  +
      Work (including but not limited to damages for loss of goodwill,
         162  +
      work stoppage, computer failure or malfunction, or any and all
         163  +
      other commercial damages or losses), even if such Contributor
         164  +
      has been advised of the possibility of such damages.
         165  +
         166  +
   9. Accepting Warranty or Additional Liability. While redistributing
         167  +
      the Work or Derivative Works thereof, You may choose to offer,
         168  +
      and charge a fee for, acceptance of support, warranty, indemnity,
         169  +
      or other liability obligations and/or rights consistent with this
         170  +
      License. However, in accepting such obligations, You may act only
         171  +
      on Your own behalf and on Your sole responsibility, not on behalf
         172  +
      of any other Contributor, and only if You agree to indemnify,
         173  +
      defend, and hold each Contributor harmless for any liability
         174  +
      incurred by, or claims asserted against, such Contributor by reason
         175  +
      of your accepting any such warranty or additional liability.

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-observability-otel/README.md

@@ -0,1 +0,7 @@
           1  +
# aws-smithy-observability-otel
           2  +
           3  +
This crate contains OpenTelemetry based implementations of the metrics traits from the `aws-smithy-observability` crate.
           4  +
           5  +
<!-- anchor_start:footer -->
           6  +
This crate is part of the [AWS SDK for Rust](https://awslabs.github.io/aws-sdk-rust/) and the [smithy-rs](https://github.com/smithy-lang/smithy-rs) code generator. In most cases, it should not be used directly.
           7  +
<!-- anchor_end:footer -->

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-observability-otel/external-types.toml

@@ -0,1 +0,11 @@
           1  +
allowed_external_types = [
           2  +
    "aws_smithy_observability::error::ObservabilityError",
           3  +
    "aws_smithy_observability::meter::AsyncMeasurement",
           4  +
    "aws_smithy_observability::meter::Histogram",
           5  +
    "aws_smithy_observability::meter::Meter",
           6  +
    "aws_smithy_observability::meter::MeterProvider",
           7  +
    "aws_smithy_observability::meter::MonotonicCounter",
           8  +
    "aws_smithy_observability::meter::UpDownCounter",
           9  +
    "aws_smithy_observability::provider::TelemetryProvider",
          10  +
    "opentelemetry_sdk::metrics::meter_provider::SdkMeterProvider",
          11  +
]

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-observability-otel/src/attributes.rs

@@ -0,1 +0,138 @@
           1  +
/*
           2  +
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
           3  +
 * SPDX-License-Identifier: Apache-2.0
           4  +
 */
           5  +
           6  +
//! Utilities to transform back and forth from Smithy Observability [Attributes] to
           7  +
//! OTel [KeyValue]s.
           8  +
           9  +
use std::ops::Deref;
          10  +
          11  +
use aws_smithy_observability::attributes::{AttributeValue, Attributes};
          12  +
use opentelemetry::{KeyValue, Value};
          13  +
          14  +
pub(crate) struct AttributesWrap(Attributes);
          15  +
impl AttributesWrap {
          16  +
    pub(crate) fn new(inner: Attributes) -> Self {
          17  +
        Self(inner)
          18  +
    }
          19  +
}
          20  +
impl Deref for AttributesWrap {
          21  +
    type Target = Attributes;
          22  +
          23  +
    fn deref(&self) -> &Self::Target {
          24  +
        &self.0
          25  +
    }
          26  +
}
          27  +
          28  +
pub(crate) fn kv_from_option_attr(input: Option<&Attributes>) -> Vec<KeyValue> {
          29  +
    input
          30  +
        .map(|attr| AttributesWrap::new(attr.clone()))
          31  +
        .unwrap_or(AttributesWrap::new(Attributes::new()))
          32  +
        .into()
          33  +
}
          34  +
          35  +
#[allow(dead_code)]
          36  +
pub(crate) fn option_attr_from_kv(input: &[KeyValue]) -> Option<Attributes> {
          37  +
    if input.is_empty() {
          38  +
        return None;
          39  +
    }
          40  +
          41  +
    Some(AttributesWrap::from(input).0)
          42  +
}
          43  +
          44  +
impl From<AttributesWrap> for Vec<KeyValue> {
          45  +
    fn from(value: AttributesWrap) -> Self {
          46  +
        value
          47  +
            .0
          48  +
            .into_attributes()
          49  +
            .map(|(k, v)| {
          50  +
                KeyValue::new(
          51  +
                    k,
          52  +
                    match v {
          53  +
                        AttributeValue::I64(val) => Value::I64(val),
          54  +
                        AttributeValue::F64(val) => Value::F64(val),
          55  +
                        AttributeValue::String(val) => Value::String(val.into()),
          56  +
                        AttributeValue::Bool(val) => Value::Bool(val),
          57  +
                        _ => Value::String("UNSUPPORTED ATTRIBUTE VALUE TYPE".into()),
          58  +
                    },
          59  +
                )
          60  +
            })
          61  +
            .collect::<Vec<KeyValue>>()
          62  +
    }
          63  +
}
          64  +
          65  +
impl From<&[KeyValue]> for AttributesWrap {
          66  +
    fn from(value: &[KeyValue]) -> Self {
          67  +
        let mut attrs = Attributes::new();
          68  +
          69  +
        value.iter().for_each(|kv| {
          70  +
            attrs.set(
          71  +
                kv.key.clone(),
          72  +
                match &kv.value {
          73  +
                    Value::Bool(val) => AttributeValue::Bool(*val),
          74  +
                    Value::I64(val) => AttributeValue::I64(*val),
          75  +
                    Value::F64(val) => AttributeValue::F64(*val),
          76  +
                    Value::String(val) => AttributeValue::String(val.clone().into()),
          77  +
                    Value::Array(_) => {
          78  +
                        AttributeValue::String("UNSUPPORTED ATTRIBUTE VALUE TYPE".into())
          79  +
                    }
          80  +
                },
          81  +
            )
          82  +
        });
          83  +
          84  +
        AttributesWrap(attrs)
          85  +
    }
          86  +
}
          87  +
          88  +
#[cfg(test)]
          89  +
mod tests {
          90  +
    use std::collections::HashMap;
          91  +
          92  +
    use super::*;
          93  +
    use aws_smithy_observability::attributes::{AttributeValue, Attributes};
          94  +
    use opentelemetry::Value;
          95  +
          96  +
    #[test]
          97  +
    fn attr_to_kv() {
          98  +
        let mut attrs = Attributes::new();
          99  +
        attrs.set("I64", AttributeValue::I64(64));
         100  +
        attrs.set("F64", AttributeValue::F64(64.0));
         101  +
        attrs.set("String", AttributeValue::String("I AM A STRING".into()));
         102  +
        attrs.set("Bool", AttributeValue::Bool(true));
         103  +
         104  +
        let kv = kv_from_option_attr(Some(&attrs));
         105  +
         106  +
        let kv_map: HashMap<String, Value> = kv
         107  +
            .into_iter()
         108  +
            .map(|kv| (kv.key.to_string(), kv.value))
         109  +
            .collect();
         110  +
         111  +
        assert_eq!(kv_map.get("I64").unwrap(), &Value::I64(64));
         112  +
        assert_eq!(kv_map.get("F64").unwrap(), &Value::F64(64.0));
         113  +
        assert_eq!(
         114  +
            kv_map.get("String").unwrap(),
         115  +
            &Value::String("I AM A STRING".into())
         116  +
        );
         117  +
        assert_eq!(kv_map.get("Bool").unwrap(), &Value::Bool(true));
         118  +
    }
         119  +
         120  +
    #[test]
         121  +
    fn kv_to_attr() {
         122  +
        let kvs: Vec<KeyValue> = vec![
         123  +
            KeyValue::new("Bool", Value::Bool(true)),
         124  +
            KeyValue::new("String", Value::String("I AM A STRING".into())),
         125  +
            KeyValue::new("I64", Value::I64(64)),
         126  +
            KeyValue::new("F64", Value::F64(64.0)),
         127  +
        ];
         128  +
         129  +
        let attrs = option_attr_from_kv(&kvs).unwrap();
         130  +
        assert_eq!(attrs.get("Bool").unwrap(), &AttributeValue::Bool(true));
         131  +
        assert_eq!(
         132  +
            attrs.get("String").unwrap(),
         133  +
            &AttributeValue::String("I AM A STRING".into())
         134  +
        );
         135  +
        assert_eq!(attrs.get("I64").unwrap(), &AttributeValue::I64(64));
         136  +
        assert_eq!(attrs.get("F64").unwrap(), &AttributeValue::F64(64.0));
         137  +
    }
         138  +
}

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-observability-otel/src/lib.rs

@@ -0,1 +0,87 @@
           1  +
/*
           2  +
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
           3  +
 * SPDX-License-Identifier: Apache-2.0
           4  +
 */
           5  +
           6  +
/* Automatically managed default lints */
           7  +
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
           8  +
/* End of automatically managed default lints */
           9  +
#![warn(
          10  +
    missing_docs,
          11  +
    rustdoc::missing_crate_level_docs,
          12  +
    unreachable_pub,
          13  +
    rust_2018_idioms
          14  +
)]
          15  +
// The `opentelemetry_sdk` crate uses std::sync::atomic::{AtomicI64, AtomicU64} which are not available on powerpc
          16  +
#![cfg(not(target_arch = "powerpc"))]
          17  +
          18  +
//! Smithy Observability OpenTelemetry
          19  +
//TODO(smithyobservability): once we have finalized everything and integrated metrics with our runtime
          20  +
// libraries update this with detailed usage docs and examples
          21  +
          22  +
pub mod attributes;
          23  +
pub mod meter;
          24  +
          25  +
#[cfg(test)]
          26  +
mod tests {
          27  +
          28  +
    use crate::meter::AwsSdkOtelMeterProvider;
          29  +
    use aws_smithy_observability::global::{get_telemetry_provider, set_telemetry_provider};
          30  +
    use aws_smithy_observability::provider::TelemetryProvider;
          31  +
    use opentelemetry_sdk::metrics::{data::Sum, PeriodicReader, SdkMeterProvider};
          32  +
    use opentelemetry_sdk::runtime::Tokio;
          33  +
    use opentelemetry_sdk::testing::metrics::InMemoryMetricsExporter;
          34  +
          35  +
    // Without these tokio settings this test just stalls forever on flushing the metrics pipeline
          36  +
    #[tokio::test(flavor = "multi_thread", worker_threads = 1)]
          37  +
    async fn can_construct_set_and_use_otel_as_global_telemetry_provider() {
          38  +
        // Create the OTel metrics objects
          39  +
        let exporter = InMemoryMetricsExporter::default();
          40  +
        let reader = PeriodicReader::builder(exporter.clone(), Tokio).build();
          41  +
        let otel_mp = SdkMeterProvider::builder().with_reader(reader).build();
          42  +
          43  +
        // Create the SDK metrics types from the OTel objects
          44  +
        let sdk_mp = AwsSdkOtelMeterProvider::new(otel_mp);
          45  +
        let sdk_tp = TelemetryProvider::builder().meter_provider(sdk_mp).build();
          46  +
          47  +
        // Set the global TelemetryProvider and then get it back out
          48  +
        let _ = set_telemetry_provider(sdk_tp);
          49  +
        let global_tp = get_telemetry_provider();
          50  +
          51  +
        // Create an instrument and record a value
          52  +
        let global_meter = global_tp
          53  +
            .meter_provider()
          54  +
            .get_meter("TestGlobalMeter", None);
          55  +
          56  +
        let mono_counter =
          57  +
            global_meter.create_monotonic_counter("TestMonoCounter".into(), None, None);
          58  +
        mono_counter.add(4, None, None);
          59  +
          60  +
        // Flush metric pipeline and extract metrics from exporter
          61  +
        global_tp
          62  +
            .meter_provider()
          63  +
            .as_any()
          64  +
            .downcast_ref::<AwsSdkOtelMeterProvider>()
          65  +
            .unwrap()
          66  +
            .shutdown()
          67  +
            .unwrap();
          68  +
        let finished_metrics = exporter.get_finished_metrics().unwrap();
          69  +
          70  +
        let extracted_mono_counter_data = &finished_metrics[0].scope_metrics[0].metrics[0]
          71  +
            .data
          72  +
            .as_any()
          73  +
            .downcast_ref::<Sum<u64>>()
          74  +
            .unwrap()
          75  +
            .data_points[0]
          76  +
            .value;
          77  +
        assert_eq!(extracted_mono_counter_data, &4);
          78  +
          79  +
        // Get the OTel TP out and shut it down
          80  +
        let foo = global_tp
          81  +
            .meter_provider()
          82  +
            .as_any()
          83  +
            .downcast_ref::<AwsSdkOtelMeterProvider>()
          84  +
            .unwrap();
          85  +
        foo.shutdown().unwrap();
          86  +
    }
          87  +
}

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-observability-otel/src/meter.rs

@@ -0,1 +0,522 @@
           1  +
/*
           2  +
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
           3  +
 * SPDX-License-Identifier: Apache-2.0
           4  +
 */
           5  +
           6  +
//! OpenTelemetry based implementations of the Smithy Observability Meter traits.
           7  +
           8  +
use std::fmt::Debug;
           9  +
use std::ops::Deref;
          10  +
          11  +
use crate::attributes::kv_from_option_attr;
          12  +
use aws_smithy_observability::attributes::{Attributes, Context};
          13  +
use aws_smithy_observability::error::{ErrorKind, ObservabilityError};
          14  +
pub use aws_smithy_observability::meter::{
          15  +
    AsyncMeasurement, Histogram, Meter, MeterProvider, MonotonicCounter, UpDownCounter,
          16  +
};
          17  +
pub use aws_smithy_observability::provider::TelemetryProvider;
          18  +
use opentelemetry::metrics::{
          19  +
    AsyncInstrument as OtelAsyncInstrument, Counter as OtelCounter, Histogram as OtelHistogram,
          20  +
    Meter as OtelMeter, MeterProvider as OtelMeterProvider,
          21  +
    ObservableCounter as OtelObservableCounter, ObservableGauge as OtelObservableGauge,
          22  +
    ObservableUpDownCounter as OtelObservableUpDownCounter, UpDownCounter as OtelUpDownCounter,
          23  +
};
          24  +
use opentelemetry_sdk::metrics::SdkMeterProvider as OtelSdkMeterProvider;
          25  +
          26  +
#[derive(Debug)]
          27  +
struct UpDownCounterWrap(OtelUpDownCounter<i64>);
          28  +
impl UpDownCounter for UpDownCounterWrap {
          29  +
    fn add(&self, value: i64, attributes: Option<&Attributes>, _context: Option<&dyn Context>) {
          30  +
        self.0.add(value, &kv_from_option_attr(attributes));
          31  +
    }
          32  +
}
          33  +
          34  +
#[derive(Debug)]
          35  +
struct HistogramWrap(OtelHistogram<f64>);
          36  +
impl Histogram for HistogramWrap {
          37  +
    fn record(&self, value: f64, attributes: Option<&Attributes>, _context: Option<&dyn Context>) {
          38  +
        self.0.record(value, &kv_from_option_attr(attributes));
          39  +
    }
          40  +
}
          41  +
          42  +
#[derive(Debug)]
          43  +
struct MonotonicCounterWrap(OtelCounter<u64>);
          44  +
impl MonotonicCounter for MonotonicCounterWrap {
          45  +
    fn add(&self, value: u64, attributes: Option<&Attributes>, _context: Option<&dyn Context>) {
          46  +
        self.0.add(value, &kv_from_option_attr(attributes));
          47  +
    }
          48  +
}
          49  +
          50  +
#[derive(Debug)]
          51  +
struct GaugeWrap(OtelObservableGauge<f64>);
          52  +
impl AsyncMeasurement for GaugeWrap {
          53  +
    type Value = f64;
          54  +
          55  +
    fn record(
          56  +
        &self,
          57  +
        value: Self::Value,
          58  +
        attributes: Option<&Attributes>,
          59  +
        _context: Option<&dyn Context>,
          60  +
    ) {
          61  +
        self.0.observe(value, &kv_from_option_attr(attributes));
          62  +
    }
          63  +
          64  +
    // OTel rust does not currently support unregistering callbacks
          65  +
    // https://github.com/open-telemetry/opentelemetry-rust/issues/2245
          66  +
    fn stop(&self) {}
          67  +
}
          68  +
          69  +
#[derive(Debug)]
          70  +
struct AsyncUpDownCounterWrap(OtelObservableUpDownCounter<i64>);
          71  +
impl AsyncMeasurement for AsyncUpDownCounterWrap {
          72  +
    type Value = i64;
          73  +
          74  +
    fn record(
          75  +
        &self,
          76  +
        value: Self::Value,
          77  +
        attributes: Option<&Attributes>,
          78  +
        _context: Option<&dyn Context>,
          79  +
    ) {
          80  +
        self.0.observe(value, &kv_from_option_attr(attributes));
          81  +
    }
          82  +
          83  +
    // OTel rust does not currently support unregistering callbacks
          84  +
    // https://github.com/open-telemetry/opentelemetry-rust/issues/2245
          85  +
    fn stop(&self) {}
          86  +
}
          87  +
          88  +
#[derive(Debug)]
          89  +
struct AsyncMonotonicCounterWrap(OtelObservableCounter<u64>);
          90  +
impl AsyncMeasurement for AsyncMonotonicCounterWrap {
          91  +
    type Value = u64;
          92  +
          93  +
    fn record(
          94  +
        &self,
          95  +
        value: Self::Value,
          96  +
        attributes: Option<&Attributes>,
          97  +
        _context: Option<&dyn Context>,
          98  +
    ) {
          99  +
        self.0.observe(value, &kv_from_option_attr(attributes));
         100  +
    }
         101  +
         102  +
    // OTel rust does not currently support unregistering callbacks
         103  +
    // https://github.com/open-telemetry/opentelemetry-rust/issues/2245
         104  +
    fn stop(&self) {}
         105  +
}
         106  +
         107  +
struct AsyncInstrumentWrap<'a, T>(&'a (dyn OtelAsyncInstrument<T> + Send + Sync));
         108  +
impl<T> AsyncMeasurement for AsyncInstrumentWrap<'_, T> {
         109  +
    type Value = T;
         110  +
         111  +
    fn record(
         112  +
        &self,
         113  +
        value: Self::Value,
         114  +
        attributes: Option<&Attributes>,
         115  +
        _context: Option<&dyn Context>,
         116  +
    ) {
         117  +
        self.0.observe(value, &kv_from_option_attr(attributes));
         118  +
    }
         119  +
         120  +
    // OTel rust does not currently support unregistering callbacks
         121  +
    // https://github.com/open-telemetry/opentelemetry-rust/issues/2245
         122  +
    fn stop(&self) {}
         123  +
}
         124  +
         125  +
// The OtelAsyncInstrument trait does not have Debug as a supertrait, so we impl a minimal version
         126  +
// for our wrapper struct
         127  +
impl<T> Debug for AsyncInstrumentWrap<'_, T> {
         128  +
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         129  +
        f.debug_tuple("AsyncInstrumentWrap").finish()
         130  +
    }
         131  +
}
         132  +
         133  +
#[derive(Debug)]
         134  +
struct MeterWrap(OtelMeter);
         135  +
impl Deref for MeterWrap {
         136  +
    type Target = OtelMeter;
         137  +
         138  +
    fn deref(&self) -> &Self::Target {
         139  +
        &self.0
         140  +
    }
         141  +
}
         142  +
         143  +
impl Meter for MeterWrap {
         144  +
    fn create_gauge(
         145  +
        &self,
         146  +
        name: String,
         147  +
        callback: Box<dyn Fn(&dyn AsyncMeasurement<Value = f64>) + Send + Sync>,
         148  +
        units: Option<String>,
         149  +
        description: Option<String>,
         150  +
    ) -> Box<dyn AsyncMeasurement<Value = f64>> {
         151  +
        let mut builder = self.f64_observable_gauge(name).with_callback(
         152  +
            move |input: &dyn OtelAsyncInstrument<f64>| {
         153  +
                callback(&AsyncInstrumentWrap(input));
         154  +
            },
         155  +
        );
         156  +
         157  +
        if let Some(desc) = description {
         158  +
            builder = builder.with_description(desc);
         159  +
        }
         160  +
         161  +
        if let Some(u) = units {
         162  +
            builder = builder.with_unit(u);
         163  +
        }
         164  +
         165  +
        Box::new(GaugeWrap(builder.init()))
         166  +
    }
         167  +
         168  +
    fn create_up_down_counter(
         169  +
        &self,
         170  +
        name: String,
         171  +
        units: Option<String>,
         172  +
        description: Option<String>,
         173  +
    ) -> Box<dyn UpDownCounter> {
         174  +
        let mut builder = self.i64_up_down_counter(name);
         175  +
        if let Some(desc) = description {
         176  +
            builder = builder.with_description(desc);
         177  +
        }
         178  +
         179  +
        if let Some(u) = units {
         180  +
            builder = builder.with_unit(u);
         181  +
        }
         182  +
         183  +
        Box::new(UpDownCounterWrap(builder.init()))
         184  +
    }
         185  +
         186  +
    fn create_async_up_down_counter(
         187  +
        &self,
         188  +
        name: String,
         189  +
        callback: Box<dyn Fn(&dyn AsyncMeasurement<Value = i64>) + Send + Sync>,
         190  +
        units: Option<String>,
         191  +
        description: Option<String>,
         192  +
    ) -> Box<dyn AsyncMeasurement<Value = i64>> {
         193  +
        let mut builder = self.i64_observable_up_down_counter(name).with_callback(
         194  +
            move |input: &dyn OtelAsyncInstrument<i64>| {
         195  +
                callback(&AsyncInstrumentWrap(input));
         196  +
            },
         197  +
        );
         198  +
         199  +
        if let Some(desc) = description {
         200  +
            builder = builder.with_description(desc);
         201  +
        }
         202  +
         203  +
        if let Some(u) = units {
         204  +
            builder = builder.with_unit(u);
         205  +
        }
         206  +
         207  +
        Box::new(AsyncUpDownCounterWrap(builder.init()))
         208  +
    }
         209  +
         210  +
    fn create_monotonic_counter(
         211  +
        &self,
         212  +
        name: String,
         213  +
        units: Option<String>,
         214  +
        description: Option<String>,
         215  +
    ) -> Box<dyn MonotonicCounter> {
         216  +
        let mut builder = self.u64_counter(name);
         217  +
        if let Some(desc) = description {
         218  +
            builder = builder.with_description(desc);
         219  +
        }
         220  +
         221  +
        if let Some(u) = units {
         222  +
            builder = builder.with_unit(u);
         223  +
        }
         224  +
         225  +
        Box::new(MonotonicCounterWrap(builder.init()))
         226  +
    }
         227  +
         228  +
    fn create_async_monotonic_counter(
         229  +
        &self,
         230  +
        name: String,
         231  +
        callback: Box<dyn Fn(&dyn AsyncMeasurement<Value = u64>) + Send + Sync>,
         232  +
        units: Option<String>,
         233  +
        description: Option<String>,
         234  +
    ) -> Box<dyn AsyncMeasurement<Value = u64>> {
         235  +
        let mut builder = self.u64_observable_counter(name).with_callback(
         236  +
            move |input: &dyn OtelAsyncInstrument<u64>| {
         237  +
                callback(&AsyncInstrumentWrap(input));
         238  +
            },
         239  +
        );
         240  +
         241  +
        if let Some(desc) = description {
         242  +
            builder = builder.with_description(desc);
         243  +
        }
         244  +
         245  +
        if let Some(u) = units {
         246  +
            builder = builder.with_unit(u);
         247  +
        }
         248  +
         249  +
        Box::new(AsyncMonotonicCounterWrap(builder.init()))
         250  +
    }
         251  +
         252  +
    fn create_histogram(
         253  +
        &self,
         254  +
        name: String,
         255  +
        units: Option<String>,
         256  +
        description: Option<String>,
         257  +
    ) -> Box<dyn Histogram> {
         258  +
        let mut builder = self.f64_histogram(name);
         259  +
        if let Some(desc) = description {
         260  +
            builder = builder.with_description(desc);
         261  +
        }
         262  +
         263  +
        if let Some(u) = units {
         264  +
            builder = builder.with_unit(u);
         265  +
        }
         266  +
         267  +
        Box::new(HistogramWrap(builder.init()))
         268  +
    }
         269  +
}
         270  +
         271  +
/// An OpenTelemetry based implementation of the AWS SDK's [MeterProvider] trait
         272  +
#[non_exhaustive]
         273  +
#[derive(Debug)]
         274  +
pub struct AwsSdkOtelMeterProvider {
         275  +
    meter_provider: OtelSdkMeterProvider,
         276  +
}
         277  +
         278  +
impl AwsSdkOtelMeterProvider {
         279  +
    /// Create a new [AwsSdkOtelMeterProvider] from an [OtelSdkMeterProvider].
         280  +
    pub fn new(otel_meter_provider: OtelSdkMeterProvider) -> Self {
         281  +
        Self {
         282  +
            meter_provider: otel_meter_provider,
         283  +
        }
         284  +
    }
         285  +
         286  +
    /// Flush the metric pipeline.
         287  +
    pub fn flush(&self) -> Result<(), ObservabilityError> {
         288  +
        match self.meter_provider.force_flush() {
         289  +
            Ok(_) => Ok(()),
         290  +
            Err(err) => Err(ObservabilityError::new(ErrorKind::MetricsFlush, err)),
         291  +
        }
         292  +
    }
         293  +
         294  +
    /// Gracefully shutdown the metric pipeline.
         295  +
    pub fn shutdown(&self) -> Result<(), ObservabilityError> {
         296  +
        match self.meter_provider.force_flush() {
         297  +
            Ok(_) => Ok(()),
         298  +
            Err(err) => Err(ObservabilityError::new(ErrorKind::MetricsShutdown, err)),
         299  +
        }
         300  +
    }
         301  +
}
         302  +
         303  +
impl MeterProvider for AwsSdkOtelMeterProvider {
         304  +
    fn get_meter(&self, scope: &'static str, _attributes: Option<&Attributes>) -> Box<dyn Meter> {
         305  +
        Box::new(MeterWrap(self.meter_provider.meter(scope)))
         306  +
    }
         307  +
         308  +
    fn as_any(&self) -> &dyn std::any::Any {
         309  +
        self
         310  +
    }
         311  +
}
         312  +
         313  +
#[cfg(test)]
         314  +
mod tests {
         315  +
         316  +
    use aws_smithy_observability::attributes::{AttributeValue, Attributes};
         317  +
    use aws_smithy_observability::meter::AsyncMeasurement;
         318  +
    use aws_smithy_observability::provider::TelemetryProvider;
         319  +
    use opentelemetry_sdk::metrics::{
         320  +
        data::{Gauge, Histogram, Sum},
         321  +
        PeriodicReader, SdkMeterProvider,
         322  +
    };
         323  +
    use opentelemetry_sdk::runtime::Tokio;
         324  +
    use opentelemetry_sdk::testing::metrics::InMemoryMetricsExporter;
         325  +
         326  +
    use super::AwsSdkOtelMeterProvider;
         327  +
         328  +
    // Without these tokio settings this test just stalls forever on flushing the metrics pipeline
         329  +
    #[tokio::test(flavor = "multi_thread", worker_threads = 1)]
         330  +
    async fn sync_instruments_work() {
         331  +
        // Create the OTel metrics objects
         332  +
        let exporter = InMemoryMetricsExporter::default();
         333  +
        let reader = PeriodicReader::builder(exporter.clone(), Tokio).build();
         334  +
        let otel_mp = SdkMeterProvider::builder().with_reader(reader).build();
         335  +
         336  +
        // Create the SDK metrics types from the OTel objects
         337  +
        let sdk_mp = AwsSdkOtelMeterProvider::new(otel_mp);
         338  +
        let sdk_tp = TelemetryProvider::builder().meter_provider(sdk_mp).build();
         339  +
         340  +
        // Get the dyn versions of the SDK metrics objects
         341  +
        let dyn_sdk_mp = sdk_tp.meter_provider();
         342  +
        let dyn_sdk_meter = dyn_sdk_mp.get_meter("TestMeter", None);
         343  +
         344  +
        //Create all 3 sync instruments and record some data for each
         345  +
        let mono_counter =
         346  +
            dyn_sdk_meter.create_monotonic_counter("TestMonoCounter".to_string(), None, None);
         347  +
        mono_counter.add(4, None, None);
         348  +
        let ud_counter =
         349  +
            dyn_sdk_meter.create_up_down_counter("TestUpDownCounter".to_string(), None, None);
         350  +
        ud_counter.add(-6, None, None);
         351  +
        let histogram = dyn_sdk_meter.create_histogram("TestHistogram".to_string(), None, None);
         352  +
        histogram.record(1.234, None, None);
         353  +
         354  +
        // Gracefully shutdown the metrics provider so all metrics are flushed through the pipeline
         355  +
        dyn_sdk_mp
         356  +
            .as_any()
         357  +
            .downcast_ref::<AwsSdkOtelMeterProvider>()
         358  +
            .unwrap()
         359  +
            .shutdown()
         360  +
            .unwrap();
         361  +
         362  +
        // Extract the metrics from the exporter and assert that they are what we expect
         363  +
        let finished_metrics = exporter.get_finished_metrics().unwrap();
         364  +
        let extracted_mono_counter_data = &finished_metrics[0].scope_metrics[0].metrics[0]
         365  +
            .data
         366  +
            .as_any()
         367  +
            .downcast_ref::<Sum<u64>>()
         368  +
            .unwrap()
         369  +
            .data_points[0]
         370  +
            .value;
         371  +
        assert_eq!(extracted_mono_counter_data, &4);
         372  +
         373  +
        let extracted_ud_counter_data = &finished_metrics[0].scope_metrics[0].metrics[1]
         374  +
            .data
         375  +
            .as_any()
         376  +
            .downcast_ref::<Sum<i64>>()
         377  +
            .unwrap()
         378  +
            .data_points[0]
         379  +
            .value;
         380  +
        assert_eq!(extracted_ud_counter_data, &-6);
         381  +
         382  +
        let extracted_histogram_data = &finished_metrics[0].scope_metrics[0].metrics[2]
         383  +
            .data
         384  +
            .as_any()
         385  +
            .downcast_ref::<Histogram<f64>>()
         386  +
            .unwrap()
         387  +
            .data_points[0]
         388  +
            .sum;
         389  +
        assert_eq!(extracted_histogram_data, &1.234);
         390  +
    }
         391  +
         392  +
    #[tokio::test(flavor = "multi_thread", worker_threads = 1)]
         393  +
    async fn async_instrument_work() {
         394  +
        // Create the OTel metrics objects
         395  +
        let exporter = InMemoryMetricsExporter::default();
         396  +
        let reader = PeriodicReader::builder(exporter.clone(), Tokio).build();
         397  +
        let otel_mp = SdkMeterProvider::builder().with_reader(reader).build();
         398  +
         399  +
        // Create the SDK metrics types from the OTel objects
         400  +
        let sdk_mp = AwsSdkOtelMeterProvider::new(otel_mp);
         401  +
        let sdk_tp = TelemetryProvider::builder().meter_provider(sdk_mp).build();
         402  +
         403  +
        // Get the dyn versions of the SDK metrics objects
         404  +
        let dyn_sdk_mp = sdk_tp.meter_provider();
         405  +
        let dyn_sdk_meter = dyn_sdk_mp.get_meter("TestMeter", None);
         406  +
         407  +
        //Create all async instruments and record some data
         408  +
        let gauge = dyn_sdk_meter.create_gauge(
         409  +
            "TestGauge".to_string(),
         410  +
            // Callback function records another value with different attributes so it is deduped
         411  +
            Box::new(|measurement: &dyn AsyncMeasurement<Value = f64>| {
         412  +
                let mut attrs = Attributes::new();
         413  +
                attrs.set(
         414  +
                    "TestGaugeAttr",
         415  +
                    AttributeValue::String("TestGaugeAttr".into()),
         416  +
                );
         417  +
                measurement.record(6.789, Some(&attrs), None);
         418  +
            }),
         419  +
            None,
         420  +
            None,
         421  +
        );
         422  +
        gauge.record(1.234, None, None);
         423  +
         424  +
        let async_ud_counter = dyn_sdk_meter.create_async_up_down_counter(
         425  +
            "TestAsyncUpDownCounter".to_string(),
         426  +
            Box::new(|measurement: &dyn AsyncMeasurement<Value = i64>| {
         427  +
                let mut attrs = Attributes::new();
         428  +
                attrs.set(
         429  +
                    "TestAsyncUpDownCounterAttr",
         430  +
                    AttributeValue::String("TestAsyncUpDownCounterAttr".into()),
         431  +
                );
         432  +
                measurement.record(12, Some(&attrs), None);
         433  +
            }),
         434  +
            None,
         435  +
            None,
         436  +
        );
         437  +
        async_ud_counter.record(-6, None, None);
         438  +
         439  +
        let async_mono_counter = dyn_sdk_meter.create_async_monotonic_counter(
         440  +
            "TestAsyncMonoCounter".to_string(),
         441  +
            Box::new(|measurement: &dyn AsyncMeasurement<Value = u64>| {
         442  +
                let mut attrs = Attributes::new();
         443  +
                attrs.set(
         444  +
                    "TestAsyncMonoCounterAttr",
         445  +
                    AttributeValue::String("TestAsyncMonoCounterAttr".into()),
         446  +
                );
         447  +
                measurement.record(123, Some(&attrs), None);
         448  +
            }),
         449  +
            None,
         450  +
            None,
         451  +
        );
         452  +
        async_mono_counter.record(4, None, None);
         453  +
         454  +
        // Gracefully shutdown the metrics provider so all metrics are flushed through the pipeline
         455  +
        dyn_sdk_mp
         456  +
            .as_any()
         457  +
            .downcast_ref::<AwsSdkOtelMeterProvider>()
         458  +
            .unwrap()
         459  +
            .shutdown()
         460  +
            .unwrap();
         461  +
         462  +
        // Extract the metrics from the exporter
         463  +
        let finished_metrics = exporter.get_finished_metrics().unwrap();
         464  +
         465  +
        // Assert that the reported metrics are what we expect
         466  +
        let extracted_gauge_data = &finished_metrics[0].scope_metrics[0].metrics[0]
         467  +
            .data
         468  +
            .as_any()
         469  +
            .downcast_ref::<Gauge<f64>>()
         470  +
            .unwrap()
         471  +
            .data_points[0]
         472  +
            .value;
         473  +
        assert_eq!(extracted_gauge_data, &1.234);
         474  +
         475  +
        let extracted_async_ud_counter_data = &finished_metrics[0].scope_metrics[0].metrics[1]
         476  +
            .data
         477  +
            .as_any()
         478  +
            .downcast_ref::<Sum<i64>>()
         479  +
            .unwrap()
         480  +
            .data_points[0]
         481  +
            .value;
         482  +
        assert_eq!(extracted_async_ud_counter_data, &-6);
         483  +
         484  +
        let extracted_async_mono_data = &finished_metrics[0].scope_metrics[0].metrics[2]
         485  +
            .data
         486  +
            .as_any()
         487  +
            .downcast_ref::<Sum<u64>>()
         488  +
            .unwrap()
         489  +
            .data_points[0]
         490  +
            .value;
         491  +
        assert_eq!(extracted_async_mono_data, &4);
         492  +
         493  +
        // Assert that the async callbacks ran
         494  +
        let finished_metrics = exporter.get_finished_metrics().unwrap();
         495  +
        let extracted_gauge_data = &finished_metrics[0].scope_metrics[0].metrics[0]
         496  +
            .data
         497  +
            .as_any()
         498  +
            .downcast_ref::<Gauge<f64>>()
         499  +
            .unwrap()
         500  +
            .data_points[1]
         501  +
            .value;
         502  +
        assert_eq!(extracted_gauge_data, &6.789);
         503  +
         504  +
        let extracted_async_ud_counter_data = &finished_metrics[0].scope_metrics[0].metrics[1]
         505  +
            .data
         506  +
            .as_any()
         507  +
            .downcast_ref::<Sum<i64>>()
         508  +
            .unwrap()
         509  +
            .data_points[1]
         510  +
            .value;
         511  +
        assert_eq!(extracted_async_ud_counter_data, &12);
         512  +
         513  +
        let extracted_async_mono_data = &finished_metrics[0].scope_metrics[0].metrics[2]
         514  +
            .data
         515  +
            .as_any()
         516  +
            .downcast_ref::<Sum<u64>>()
         517  +
            .unwrap()
         518  +
            .data_points[1]
         519  +
            .value;
         520  +
        assert_eq!(extracted_async_mono_data, &123);
         521  +
    }
         522  +
}

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-observability/Cargo.toml

@@ -0,1 +0,24 @@
           1  +
# Code generated by software.amazon.smithy.rust.codegen.smithy-rs. DO NOT EDIT.
           2  +
[package]
           3  +
name = "aws-smithy-observability"
           4  +
version = "0.1.0"
           5  +
authors = ["AWS Rust SDK Team <aws-sdk-rust@amazon.com>"]
           6  +
description = "Smithy observability implementation."
           7  +
edition = "2021"
           8  +
license = "Apache-2.0"
           9  +
repository = "https://github.com/awslabs/smithy-rs"
          10  +
[package.metadata.docs.rs]
          11  +
all-features = true
          12  +
targets = ["x86_64-unknown-linux-gnu"]
          13  +
cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"]
          14  +
rustdoc-args = ["--cfg", "docsrs"]
          15  +
          16  +
[dependencies]
          17  +
once_cell = "1.19.0"
          18  +
          19  +
[dependencies.aws-smithy-runtime-api]
          20  +
path = "../aws-smithy-runtime-api"
          21  +
version = "1.7.3"
          22  +
          23  +
[dev-dependencies]
          24  +
serial_test = "3.1.1"

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-observability/LICENSE

@@ -0,1 +0,175 @@
           1  +
           2  +
                                 Apache License
           3  +
                           Version 2.0, January 2004
           4  +
                        http://www.apache.org/licenses/
           5  +
           6  +
   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
           7  +
           8  +
   1. Definitions.
           9  +
          10  +
      "License" shall mean the terms and conditions for use, reproduction,
          11  +
      and distribution as defined by Sections 1 through 9 of this document.
          12  +
          13  +
      "Licensor" shall mean the copyright owner or entity authorized by
          14  +
      the copyright owner that is granting the License.
          15  +
          16  +
      "Legal Entity" shall mean the union of the acting entity and all
          17  +
      other entities that control, are controlled by, or are under common
          18  +
      control with that entity. For the purposes of this definition,
          19  +
      "control" means (i) the power, direct or indirect, to cause the
          20  +
      direction or management of such entity, whether by contract or
          21  +
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
          22  +
      outstanding shares, or (iii) beneficial ownership of such entity.
          23  +
          24  +
      "You" (or "Your") shall mean an individual or Legal Entity
          25  +
      exercising permissions granted by this License.
          26  +
          27  +
      "Source" form shall mean the preferred form for making modifications,
          28  +
      including but not limited to software source code, documentation
          29  +
      source, and configuration files.
          30  +
          31  +
      "Object" form shall mean any form resulting from mechanical
          32  +
      transformation or translation of a Source form, including but
          33  +
      not limited to compiled object code, generated documentation,
          34  +
      and conversions to other media types.
          35  +
          36  +
      "Work" shall mean the work of authorship, whether in Source or
          37  +
      Object form, made available under the License, as indicated by a
          38  +
      copyright notice that is included in or attached to the work
          39  +
      (an example is provided in the Appendix below).
          40  +
          41  +
      "Derivative Works" shall mean any work, whether in Source or Object
          42  +
      form, that is based on (or derived from) the Work and for which the
          43  +
      editorial revisions, annotations, elaborations, or other modifications
          44  +
      represent, as a whole, an original work of authorship. For the purposes
          45  +
      of this License, Derivative Works shall not include works that remain
          46  +
      separable from, or merely link (or bind by name) to the interfaces of,
          47  +
      the Work and Derivative Works thereof.
          48  +
          49  +
      "Contribution" shall mean any work of authorship, including
          50  +
      the original version of the Work and any modifications or additions
          51  +
      to that Work or Derivative Works thereof, that is intentionally
          52  +
      submitted to Licensor for inclusion in the Work by the copyright owner
          53  +
      or by an individual or Legal Entity authorized to submit on behalf of
          54  +
      the copyright owner. For the purposes of this definition, "submitted"
          55  +
      means any form of electronic, verbal, or written communication sent
          56  +
      to the Licensor or its representatives, including but not limited to
          57  +
      communication on electronic mailing lists, source code control systems,
          58  +
      and issue tracking systems that are managed by, or on behalf of, the
          59  +
      Licensor for the purpose of discussing and improving the Work, but
          60  +
      excluding communication that is conspicuously marked or otherwise
          61  +
      designated in writing by the copyright owner as "Not a Contribution."
          62  +
          63  +
      "Contributor" shall mean Licensor and any individual or Legal Entity
          64  +
      on behalf of whom a Contribution has been received by Licensor and
          65  +
      subsequently incorporated within the Work.
          66  +
          67  +
   2. Grant of Copyright License. Subject to the terms and conditions of
          68  +
      this License, each Contributor hereby grants to You a perpetual,
          69  +
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
          70  +
      copyright license to reproduce, prepare Derivative Works of,
          71  +
      publicly display, publicly perform, sublicense, and distribute the
          72  +
      Work and such Derivative Works in Source or Object form.
          73  +
          74  +
   3. Grant of Patent License. Subject to the terms and conditions of
          75  +
      this License, each Contributor hereby grants to You a perpetual,
          76  +
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
          77  +
      (except as stated in this section) patent license to make, have made,
          78  +
      use, offer to sell, sell, import, and otherwise transfer the Work,
          79  +
      where such license applies only to those patent claims licensable
          80  +
      by such Contributor that are necessarily infringed by their
          81  +
      Contribution(s) alone or by combination of their Contribution(s)
          82  +
      with the Work to which such Contribution(s) was submitted. If You
          83  +
      institute patent litigation against any entity (including a
          84  +
      cross-claim or counterclaim in a lawsuit) alleging that the Work
          85  +
      or a Contribution incorporated within the Work constitutes direct
          86  +
      or contributory patent infringement, then any patent licenses
          87  +
      granted to You under this License for that Work shall terminate
          88  +
      as of the date such litigation is filed.
          89  +
          90  +
   4. Redistribution. You may reproduce and distribute copies of the
          91  +
      Work or Derivative Works thereof in any medium, with or without
          92  +
      modifications, and in Source or Object form, provided that You
          93  +
      meet the following conditions:
          94  +
          95  +
      (a) You must give any other recipients of the Work or
          96  +
          Derivative Works a copy of this License; and
          97  +
          98  +
      (b) You must cause any modified files to carry prominent notices
          99  +
          stating that You changed the files; and
         100  +
         101  +
      (c) You must retain, in the Source form of any Derivative Works
         102  +
          that You distribute, all copyright, patent, trademark, and
         103  +
          attribution notices from the Source form of the Work,
         104  +
          excluding those notices that do not pertain to any part of
         105  +
          the Derivative Works; and
         106  +
         107  +
      (d) If the Work includes a "NOTICE" text file as part of its
         108  +
          distribution, then any Derivative Works that You distribute must
         109  +
          include a readable copy of the attribution notices contained
         110  +
          within such NOTICE file, excluding those notices that do not
         111  +
          pertain to any part of the Derivative Works, in at least one
         112  +
          of the following places: within a NOTICE text file distributed
         113  +
          as part of the Derivative Works; within the Source form or
         114  +
          documentation, if provided along with the Derivative Works; or,
         115  +
          within a display generated by the Derivative Works, if and
         116  +
          wherever such third-party notices normally appear. The contents
         117  +
          of the NOTICE file are for informational purposes only and
         118  +
          do not modify the License. You may add Your own attribution
         119  +
          notices within Derivative Works that You distribute, alongside
         120  +
          or as an addendum to the NOTICE text from the Work, provided
         121  +
          that such additional attribution notices cannot be construed
         122  +
          as modifying the License.
         123  +
         124  +
      You may add Your own copyright statement to Your modifications and
         125  +
      may provide additional or different license terms and conditions
         126  +
      for use, reproduction, or distribution of Your modifications, or
         127  +
      for any such Derivative Works as a whole, provided Your use,
         128  +
      reproduction, and distribution of the Work otherwise complies with
         129  +
      the conditions stated in this License.
         130  +
         131  +
   5. Submission of Contributions. Unless You explicitly state otherwise,
         132  +
      any Contribution intentionally submitted for inclusion in the Work
         133  +
      by You to the Licensor shall be under the terms and conditions of
         134  +
      this License, without any additional terms or conditions.
         135  +
      Notwithstanding the above, nothing herein shall supersede or modify
         136  +
      the terms of any separate license agreement you may have executed
         137  +
      with Licensor regarding such Contributions.
         138  +
         139  +
   6. Trademarks. This License does not grant permission to use the trade
         140  +
      names, trademarks, service marks, or product names of the Licensor,
         141  +
      except as required for reasonable and customary use in describing the
         142  +
      origin of the Work and reproducing the content of the NOTICE file.
         143  +
         144  +
   7. Disclaimer of Warranty. Unless required by applicable law or
         145  +
      agreed to in writing, Licensor provides the Work (and each
         146  +
      Contributor provides its Contributions) on an "AS IS" BASIS,
         147  +
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
         148  +
      implied, including, without limitation, any warranties or conditions
         149  +
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
         150  +
      PARTICULAR PURPOSE. You are solely responsible for determining the
         151  +
      appropriateness of using or redistributing the Work and assume any
         152  +
      risks associated with Your exercise of permissions under this License.
         153  +
         154  +
   8. Limitation of Liability. In no event and under no legal theory,
         155  +
      whether in tort (including negligence), contract, or otherwise,
         156  +
      unless required by applicable law (such as deliberate and grossly
         157  +
      negligent acts) or agreed to in writing, shall any Contributor be
         158  +
      liable to You for damages, including any direct, indirect, special,
         159  +
      incidental, or consequential damages of any character arising as a
         160  +
      result of this License or out of the use or inability to use the
         161  +
      Work (including but not limited to damages for loss of goodwill,
         162  +
      work stoppage, computer failure or malfunction, or any and all
         163  +
      other commercial damages or losses), even if such Contributor
         164  +
      has been advised of the possibility of such damages.
         165  +
         166  +
   9. Accepting Warranty or Additional Liability. While redistributing
         167  +
      the Work or Derivative Works thereof, You may choose to offer,
         168  +
      and charge a fee for, acceptance of support, warranty, indemnity,
         169  +
      or other liability obligations and/or rights consistent with this
         170  +
      License. However, in accepting such obligations, You may act only
         171  +
      on Your own behalf and on Your sole responsibility, not on behalf
         172  +
      of any other Contributor, and only if You agree to indemnify,
         173  +
      defend, and hold each Contributor harmless for any liability
         174  +
      incurred by, or claims asserted against, such Contributor by reason
         175  +
      of your accepting any such warranty or additional liability.