diff --git a/src/content/docs/agile-handbook/heroing/what-is-a-hero.mdx b/src/content/docs/agile-handbook/heroing/what-is-a-hero.mdx index fc209afc6be..7b6d00afb3c 100644 --- a/src/content/docs/agile-handbook/heroing/what-is-a-hero.mdx +++ b/src/content/docs/agile-handbook/heroing/what-is-a-hero.mdx @@ -1,14 +1,19 @@ --- -title: "What is a hero?" +title: "What is a hero? What is a sidekick?" template: basicDoc topics: - Docs agile handbook -freshnessValidatedDate: never +freshnessValidatedDate: 2024-02-06 --- "Hero" is a common term across New Relic for a dedicated, interruptible person who acts as an interface for a team. When you're a docs hero, you're the face of the team. -We have two heroes at any given time: the GitHub hero (for issues and pull requests) and the Slack hero (for questions through Slack). We also have a second-shift hero to support EMEA Relics. Every hero's job is to keep things moving for Relics and users. We change GitHub and heroes once a day (we used to do weekly shifts, but we've found daily shifts reduce hero burnout). +We have two rotating roles at any given time: + +* The Hero handles Slack questions, reviews pull requests, and triages GitHub issues +* The CSAT Sidekick handles customer feedback coming in through Jira. + +Both roles are here to keep docs requests moving for Relics and users, and to give the team a buffer from interruptions. We change hero and a sidekick once a week (we used to do daily shifts, but we've found the daily cadence to be too disruptive and lead to work that bleeds over to the next day). ## Goals for heroing [#heroing-goals] @@ -30,7 +35,7 @@ As the hero, you're often pulled in a lot of directions in a given shift. Becaus You're also not expected to know everything as a hero! If something comes up for which you have no easy answer, let the requestor know you're on it and then ping your fellow writers or other SMEs and helpers from across New Relic for help. -## GitHub hero responsibilities [#gh_hero_responsibilities] +## Hero GitHub responsibilities [#gh_hero_responsibilities] The GitHub hero monitors the GitHub board and the flow of work through GitHub. @@ -62,9 +67,9 @@ To merge, just [click this magic link](https://github.com/newrelic/docs-website/ During super busy shifts, you likely won't have time for many of these, but if you're having a slow shift please take some time to periodically check the **Writer Needs Peer Edit** swim lane for fresh peer edit asks from your teammates before you switch over to doing sprint work. -## Slack hero responsibilities +## Hero Slack responsibilities [#slack_hero_responsibilities] -The Slack hero monitors Slack and helps answer questions about docs and route people to the right resource on the team. +We use Slack to help answer questions about docs and route people to the right resource on the team. ### Update the Slack alias @@ -81,32 +86,10 @@ Common questions and requests include: * **Questions about status of a pull request or issue**. Check in and see if you can figure out, or pull in the assignee for that pull request if the status isn't clear. * **Questions about things we don't own (blog, API Explorer, newrelic.com, etc)**. Help them out by directing them to the appropriate Slack channel. (For a list of properties and their owner, see _Who owns the other wesbites?_ in Google Docs.) If you can't figure out who owns it, try asking the writing team in Slack. -## Second-shift hero support +## Second-shift hero support [#emea_support] Our Europe writers cover the 2nd shift heroing during their regular working hours. Unlike the US-based heroes, our Barcelona writers hero for an entire two-week sprint. Second-shift heroes cover both GitHub and Slack, but we don't expect that second-shift heroes will field every single request that comes in during their working hours since they're also carrying standard sprint duties during their hero shift. -## Route and triage user feedback - -The hero is responsible for routing user feedback to liasions. This sections covers the entire lifecycle of a user feedback ticket: - -1. The hero is responsible for routing incoming tickets to the proper liaison each day - - The Hero leaves a comment saying the ticket is being triaged -2. Each writer should spend 10-15 minutes/day triaging their assigned tickets - - Writer either rewrites or closes the ticket - - If the writer closes the ticket, they must leave a comment explaining why. - - Writer needs to add: - - Acceptance criteria - - User story - - Action items - - Resources - - While rewriting, focus on making the ticket as swarmable as possible - - Assign a priority [See priority info in our team's `DOC Jira and Github fields - Project 401 - 2022` doc] - - Add the following label: `doc_groomed` -3. Triaged tickets enter sprints in one of two ways: - - **Scrum leaders**: Bring in tickets based on marked priority - - **Liaisons**: Bring in high value issues - - **Squads**: During backlog grooming the team can chat about bringing in tickets to fill out a sprint - For writers in Europe: @@ -114,6 +97,92 @@ For writers in Europe: - You should still triage issues routed to you from your liaisonships once per day. +## Customer feedback sidekick [#cf_sidekick] + +Feedback is a gift. Every piece of meaningful feedback represents someone taking time out of their day to express something to us. It's important that we honor that gift. Our team created the sidekick role so that we regularly have a human being reading through and thinking about and responding to every piece of feedback that people write to us. + +As valuable as this feedback is, though, **our primary goal is to keep our Jira backlog down to a manageable and reasonable size**. + +Customer feedback from our docs site creates tickets in Jira. It's the sidekick's responsibility to look at every ticket that comes in (usually about 5–10 per day) and make decisions about each one. + +There are three options for these tickets: + +1. Close it. +2. Fix it. +3. Backlog it. + + +Unlike the hero, we don't take any points out of our sprint for the sidekick work. If you're spending more than 60 minutes per day on customer feedback tickets, that's too much time! Please let your manager know. + + +### Close customer feedback + +Many pieces of customer feedback simply aren't actionable. That's ok! Even if we can't act on a specific piece of feedback, we can use this collective feedback to get an overall sense of how our docs site or a specific category of our docs site is landing with our readers. + +Here are some fictional examples of feedback we might not be able to act on specifically: + +`These docs are bad.` + +or + +`Help!` + +There's also feedback that falls into the category of nonsense or mistakes. You'll know it when you see it. Comments like this can be closed immediately. + +Follow this process to close tickets that aren't actionable or don't make sense: + +1. Add a category label based on the URL, such as `doc_apm` or `doc_errors-inbox`. +2. Set the Workflow status to **Closed** +3. Set the Resolution to **Cannot Reproduce**, **Filed by Mistake**, or **Won't Do** depending on what feels most appropriate. +4. Add a brief note about why you closed it. Usually, "Not actionable" is plenty. + +### Fix customer feedback + +Sometimes, though rarely, a customer feedback ticket comes in that's highly actionable and is a quick fix, such as a broken link or an outdated image. If you need to reach out to a subject matter expert, the ticket is **probably not** a quick fix. + +Follow this process to close these: + +1. Create a PR to address the issue. +1. Add a category label based on the URL, such as `doc_apm` or `doc_errors-inbox` (These labels are based off of the first part of the URL after `/docs/. For example, `https://docs.newrelic.com/docs/errors-inbox` would have the label `docs_errors-inbox`.). +1. Add a link to the PR. +1. Work the PR to its merge at your leisure. +1. Set the Jira ticket Workflow status to **Closed** +1. Set the Jira ticket Resolution to **Done**. + +### Backlog customer feedback + +Too many ticket backlogs have a larger quantity of tickets than can ever be addressed. Our team's goal is to get our customer feedback backlog down to a small enough number that we can meaningfully and reasonably address them in a few sprints based on our current headcount and capacity. Because of this, we need to set a pretty high bar for adding a ticket to our backlog. + +Sometimes a piece of customer feedback is quite valid, but the scope of the work required to address it isn't something our team can't commit to right now. Sometimes a comment requires technological knowledge that we don't have. Sometimes a doc simply doesn't get enough traffic to warrant fixing a problem right away. + +If you're not sure whether a ticket belongs in our backlog, ask your manager or put it into the On Deck sprint to ensure it doesn't fall through the cracks. + +Use this process to put a ticket in the backlog: + +1. Write a user story. +2. Write acceptance criteria. +3. Write loose action items. +4. Add any other detail about what you've learned. +5. **Move** the ticket from the Customer Feedback to Story ticket type. +6. Add the ticket to our Docs On Deck sprint. + +### Customer email + +There's no expectation that you email customers back regarding their feedback. However, when you respond to customers in a timely way, you can: + +* Build goodwill +* Learn more about what works and doesn't work in our docs +* Clarify what's going on with the feedback +* Give more useful product feedback to our PMs + +When you write an email to a customer, don't send them a boilerplate message. Be sure to write a genuine, thoughtful response to their feedback that either answers their question or asks meaningful questions. You may not get a response and that's OK. In most cases, people are delighted to hear back from a real human being and there's a good chance that you'll learn a little something about our docs and our platform, too! + +### Customer feedback in aggregate + +Even if a single piece of customer feedback is closed and we haven't acted on it, that doesn't mean it stop being useful. When you begin to consider improving a doc or a category of docs on our site, use Jira filters to find customer feedback related to those. For example, if 20 people are expressing confusion at the doc you're looking at, you should consider how to make it less so. + +Make reviewing customer feedback for specific docs categories a part of your editing process. + - This option requires that you have `AWSLambdaBasicExecutionRole` or an equivalent policy attached to your function. + Enabling X-Ray is no longer needed, because `DisableAwsXRayContextExtraction` is set to `true` in the AWS OTel .NET SDK for Lambda. You can find more details in the [AWS OTel .NET SDK for Lambda Readme](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/blob/main/src/OpenTelemetry.Instrumentation.AWSLambda/README.md#instrumentation). -## Step 2: Install the layer [#install] + + +## Install the layer [#install] AWS publishes a managed layer that includes the [OpenTelemetry Lambda Collector](https://github.com/open-telemetry/opentelemetry-lambda). @@ -64,10 +41,10 @@ To install it: 3. Under **Specify an ARN**, paste one of the layer ARNs for your function's architecture from the list below. Replace `{region}`with your AWS region, such as `us-east-1`. 4. Choose **Add**. -* AMD64 / X86_64: `arn:aws:lambda:{region}:901920570463:layer:aws-otel-collector-amd64-ver-0-45-0:2` -* ARM64: `arn:aws:lambda:\:901920570463:layer:aws-otel-collector-arm64-ver-0-45-0:2` +* AMD64 / X86_64: `arn:aws:lambda:{region}:901920570463:layer:aws-otel-collector-amd64-ver-0-90-1:1` +* ARM64: `arn:aws:lambda:\:901920570463:layer:aws-otel-collector-arm64-ver-0-90-1:1` -For SAM and CloudFormation templates, add the following to your function's properties. Be sure to replace `your-license-key-here` with your and `otlp.nr-data.net:4317` with the New Relic OpenTelemetry Endpoint for your region. +For SAM and CloudFormation templates, add the following to your function's properties: ```yaml yourFunctionHere: @@ -76,16 +53,17 @@ For SAM and CloudFormation templates, add the following to your function's prope ... Layers: # Use this if using x86_64 architecture - - !Sub arn:${AWS::Partition}:lambda:${AWS::Region}:901920570463:layer:aws-otel-collector-amd64-ver-0-45-0:2 + - !Sub arn:${AWS::Partition}:lambda:${AWS::Region}:901920570463:layer:aws-otel-collector-amd64-ver-0-90-1:1 # Use this if using arm64 architecture - - !Sub arn:${AWS::Partition}:lambda:${AWS::Region}:901920570463:layer:aws-otel-collector-arm64-ver-0-45-0:2 + - !Sub arn:${AWS::Partition}:lambda:${AWS::Region}:901920570463:layer:aws-otel-collector-arm64-ver-0-90-1:1 ``` Refer to the [latest ARNs published by AWS](https://aws-otel.github.io/docs/getting-started/lambda/lambda-dotnet) to verify the layer ARNs above are up to date. - - -## Step 3: Add New Relic environment variables [#env-variables] + + + +## Add New Relic environment variables [#env-variables] To send the OpenTelemetry data that this layer collects to New Relic, we need to configure the OpenTelemetry Lambda Collector that is packaged with the layer to export the telemetry it receives to the [New Relic OpenTelemetry Endpoint](/docs/more-integrations/open-source-telemetry-integrations/opentelemetry/opentelemetry-quick-start). Before we do that, we first need to set some environment variables that it will depend upon. @@ -120,9 +98,10 @@ For SAM and CloudFormation templates, add the following to your function's prope Replace `your-license-key-here` with your New Relic and `otlp.nr-data.net:4317` with the endpoint appropriate for your New Relic region (see list above). - - -## Step 4: Configure the collector [#collector] + + + +## Configure the collector [#collector] Now we will override the OpenTelemetry Lambda Collector's default configuration with one that exports telemetry to the New Relic OpenTelemetry Endpoint. To do this we must include a `collector.yaml` config file with our function. @@ -190,15 +169,18 @@ For SAM and CloudFormation templates, add this to your function's properties: This assumes you bundled your `collector.yaml` in your function's root directory. If you bundled it somewhere else, replace `/var/task/collector.yaml` with the path to your `collector.yaml`. - + + + +## Instrument Your Function [#instrument] -## Step 5: Instrument Your Function [#instrument] - -First add the [OpenTelemetry SDK for AWS Lambda](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.AWSLambda/), as well as the [OTLP exporter package](https://www.nuget.org/packages/OpenTelemetry.Exporter.OpenTelemetryProtocol). +First add the [OpenTelemetry SDK for AWS Lambda](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.AWSLambda/), as well as the [OTLP exporter package](https://www.nuget.org/packages/OpenTelemetry.Exporter.OpenTelemetryProtocol). You can add more OpenTelemetry instrumentation packages, such as [OpenTelemetry.Instrumentation.AWS](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.AWS) and [OpenTelemetry.Instrumentation.Http](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.Http), to get additional visibility into your function's behavior. ```bash dotnet add package OpenTelemetry.Instrumentation.AWSLambda dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol +dotnet add package OpenTelemetry.Instrumentation.AWS +dotnet add package OpenTelemetry.Instrumentation.Http ``` Add calls to `AddAWSLambdaConfigurations()` and `AddOtlpExporter()` from `TracerProvider` in your function's static constructor. @@ -210,11 +192,15 @@ Add calls to `AddAWSLambdaConfigurations()` and `AddOtlpExporter()` from `Tracer ```csharp TracerProvider tracerProvider = Sdk.CreateTracerProviderBuilder() // add other instrumentations here - .AddAWSLambdaConfigurations() + .AddAWSLambdaConfigurations(options => options.DisableAwsXRayContextExtraction = true) .AddOtlpExporter() .Build(); ``` + + Be sure to set the `DisableAwsXRayContextExtraction` property to `true` if you don't enable X-Ray. Otherwise, traces will not be instrumented. + + Create a wrapper function with the same signature as the original Lambda handler function. Call `AWSLambdaWrapper.Trace()` API and pass `TracerProvider`, the original Lambda function, and its inputs as parameters. ```csharp @@ -227,9 +213,29 @@ public string OriginalFunctionHandler(JObject input, ILambdaContext context) { } ``` +If your original handler is an async function, use the `TraceAsync()` API instead of `Trace()`. + +```csharp +public Task TracingFunctionHandler(APIGatewayProxyRequest request, + ILambdaContext context) + => AWSLambdaWrapper.TraceAsync(tracerProvider, OriginalFunctionHandler, request, context); + +public async Task OriginalFunctionHandler(APIGatewayProxyRequest apigProxyEvent, ILambdaContext context) +{ + //your function here. +} +``` + For example, a basic API Gateway Lambda function would look like this: ```csharp +using System; +using Amazon.Lambda.APIGatewayEvents; +using Amazon.Lambda.Core; +using OpenTelemetry; +using OpenTelemetry.Instrumentation.AWSLambda; +using OpenTelemetry.Trace; + namespace Example { public class Function @@ -239,30 +245,29 @@ namespace Example static Function() { tracerProvider = Sdk.CreateTracerProviderBuilder() - .AddAWSInstrumentation() - .AddAWSLambdaConfigurations() + .AddAWSLambdaConfigurations(options => options.DisableAwsXRayContextExtraction = true) .AddOtlpExporter() .Build(); - } - // use AwsSdkSample::AwsSdkSample.Function::TracingFunctionHandler as input Lambda handler instead - public APIGatewayProxyResponse TracingFunctionHandler(APIGatewayProxyRequest request, ILambdaContext context) - { - return AWSLambdaWrapper.Trace(tracerProvider, FunctionHandler, request, context); - } - - /// - /// A simple function that takes a APIGatewayProxyRequest and returns a APIGatewayProxyResponse - /// - /// - /// - /// - public APIGatewayProxyResponse FunctionHandler(APIGatewayProxyRequest request, ILambdaContext context) - { - return new APIGatewayProxyResponse() { - StatusCode = 200, - Body = Environment.GetEnvironmentVariable("_X_AMZN_TRACE_ID") - }; + // use AwsSdkSample::AwsSdkSample.Function::TracingFunctionHandler as input Lambda handler instead + public APIGatewayProxyResponse TracingFunctionHandler(APIGatewayProxyRequest request, ILambdaContext context) + { + return AWSLambdaWrapper.Trace(tracerProvider, FunctionHandler, request, context); + } + + /// + /// A simple function that takes a APIGatewayProxyRequest and returns a APIGatewayProxyResponse + /// + /// + /// + /// + public APIGatewayProxyResponse FunctionHandler(APIGatewayProxyRequest request, ILambdaContext context) + { + return new APIGatewayProxyResponse() { + StatusCode = 200, + Body = Environment.GetEnvironmentVariable("_X_AMZN_TRACE_ID") + }; + } } } } @@ -272,13 +277,16 @@ Then set the wrapper function as the Lambda function's handler. For the class ab For a working example, including tracing the AWS SDK, see [this sample app](https://github.com/open-telemetry/opentelemetry-lambda/blob/main/dotnet/sample-apps/aws-sdk/wrapper/SampleApps/AwsSdkSample/Function.cs). -The above is just a basic example, for more advanced instrumentation refer to the [OpenTelemetry .NET SDK documentation](https://github.com/open-telemetry/opentelemetry-dotnet). - -## Step 6: View your data in the New Relic UI [#view-data] +The above is just a basic example, for more advanced instrumentation refer to the [OpenTelemetry .NET SDK documentation](https://github.com/open-telemetry/opentelemetry-dotnet). + + +## View your data in the New Relic UI [#view-data] First you will want to [invoke your Lambda function](https://docs.aws.amazon.com/lambda/latest/dg/lambda-invocation.html) a few times to start generating telemetry. From there, head over to New Relic to find your [traces](https://one.newrelic.com/launcher/nr1-core.explorer?overlay=eyJuZXJkbGV0SWQiOiJkYXRhLWV4cGxvcmF0aW9uLnF1ZXJ5LWJ1aWxkZXIiLCJpbml0aWFsQWN0aXZlSW50ZXJmYWNlIjoibnJxbEVkaXRvciIsImluaXRpYWxOcnFsVmFsdWUiOiIiLCJpbml0aWFsUXVlcmllcyI6W3sibnJxbCI6IkZST00gU3BhbiBTRUxFQ1QgY291bnQoKikgd2hlcmUgbmV3cmVsaWMuc291cmNlPSclb3RscCUnIFRJTUVTRVJJRVMifV0sImluaXRpYWxDaGFydFNldHRpbmdzIjp7ImNoYXJ0VHlwZSI6IkNIQVJUX0xJTkUiLCJsaW1pdCI6NzU0MiwibGlua2VkRW50aXR5R3VpZCI6bnVsbCwibGlua2VkRGFzaGJvYXJkSWQiOm51bGwsInlTY2FsZSI6eyJzdGF0aWMiOmZhbHNlLCJkb21haW4iOltudWxsLG51bGxdfSwieVplcm8iOnRydWV9fQo=), [metrics](https://one.newrelic.com/launcher/nr1-core.explorer?overlay=eyJuZXJkbGV0SWQiOiJkYXRhLWV4cGxvcmF0aW9uLnF1ZXJ5LWJ1aWxkZXIiLCJpbml0aWFsQWN0aXZlSW50ZXJmYWNlIjoibnJxbEVkaXRvciIsImluaXRpYWxOcnFsVmFsdWUiOiIiLCJpbml0aWFsUXVlcmllcyI6W3sibnJxbCI6IkZST00gTWV0cmljIFNFTEVDVCBjb3VudCgqKSB3aGVyZSBuZXdyZWxpYy5zb3VyY2UgTElLRSAnJW90bHAlJyBUSU1FU0VSSUVTIn1dLCJpbml0aWFsQ2hhcnRTZXR0aW5ncyI6eyJjaGFydFR5cGUiOiJDSEFSVF9MSU5FIiwibGltaXQiOjc1NDIsImxpbmtlZEVudGl0eUd1aWQiOm51bGwsImxpbmtlZERhc2hib2FyZElkIjpudWxsLCJ5U2NhbGUiOnsic3RhdGljIjpmYWxzZSwiZG9tYWluIjpbbnVsbCxudWxsXX0sInlaZXJvIjp0cnVlfX0K), and [logs](https://one.newrelic.com/launcher/nr1-core.explorer?overlay=eyJuZXJkbGV0SWQiOiJkYXRhLWV4cGxvcmF0aW9uLnF1ZXJ5LWJ1aWxkZXIiLCJpbml0aWFsQWN0aXZlSW50ZXJmYWNlIjoibnJxbEVkaXRvciIsImluaXRpYWxOcnFsVmFsdWUiOiIiLCJpbml0aWFsUXVlcmllcyI6W3sibnJxbCI6IkZST00gTG9nIFNFTEVDVCBjb3VudCgqKSB3aGVyZSBuZXdyZWxpYy5zb3VyY2U9JyVvdGxwJScgVElNRVNFUklFUyJ9XSwiaW5pdGlhbENoYXJ0U2V0dGluZ3MiOnsiY2hhcnRUeXBlIjoiQ0hBUlRfTElORSIsImxpbWl0Ijo3NTQyLCJsaW5rZWRFbnRpdHlHdWlkIjpudWxsLCJsaW5rZWREYXNoYm9hcmRJZCI6bnVsbCwieVNjYWxlIjp7InN0YXRpYyI6ZmFsc2UsImRvbWFpbiI6W251bGwsbnVsbF19LCJ5WmVybyI6dHJ1ZX19Cg==). -Your telemetry will not appear under New Relic Serverless. Instead, you will find your telemetry data under the New Relic OpenTelemetry Nerdlets. +Your telemetry will not appear under New Relic Serverless. Instead, you will find your telemetry data under the New Relic OpenTelemetry Nerdlets. + + ## Distributed Tracing [#distributed-tracing] diff --git a/src/content/docs/style-guide/writing-docs/processes-procedures/use-content-types-text-formats.mdx b/src/content/docs/style-guide/writing-docs/processes-procedures/use-content-types-text-formats.mdx index 1b9a5ce60c2..2e21d36262c 100644 --- a/src/content/docs/style-guide/writing-docs/processes-procedures/use-content-types-text-formats.mdx +++ b/src/content/docs/style-guide/writing-docs/processes-procedures/use-content-types-text-formats.mdx @@ -89,6 +89,18 @@ The top of every doc begins with a set of metadata. Read on for more information The URL to the Japanese language version of the doc. Leave this blank if there isn't a Japanese version. + + + + + freshnessValidatedDate + + + + The default is `never`. + + When you make a significant update to a doc, add today's date in this format: `YYYY-MM-DD`. + diff --git a/src/data/whats-new-ids.json b/src/data/whats-new-ids.json index 36cc223d9b4..4dbeffcbf56 100644 --- a/src/data/whats-new-ids.json +++ b/src/data/whats-new-ids.json @@ -305,5 +305,6 @@ "/whats-new/2024/01/whats-new-01-22-deprecating-ic-limits": "42958", "/whats-new/2024/01/whats-new-01-24-javaagent8": "42959", "/whats-new/2024/01/whats-new-01-25-codestream": "42960", - "/whats-new/2021/10/python-update-7-0-0-166": "42961" + "/whats-new/2021/10/python-update-7-0-0-166": "42961", + "/whats-new/2024/02/whats-new-02-21-new-query-experience": "42962" } \ No newline at end of file