-
Notifications
You must be signed in to change notification settings - Fork 403
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* develop: docs: add CW Logs as a supported envelope fix: cloudwatch logs envelope typo docs: add CW Logs as a supported model docs: add Alb as a supported model docs: shadow sidebar to remain expanded cr fixes feat: Add cloudwatch lambda event support to Parser utility feat: Add alb lambda event support to Parser utility #228
- Loading branch information
Showing
13 changed files
with
1,014 additions
and
1 deletion.
There are no files selected for viewing
10 changes: 9 additions & 1 deletion
10
aws_lambda_powertools/utilities/parser/envelopes/__init__.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,15 @@ | ||
from .base import BaseEnvelope | ||
from .cloudwatch import CloudWatchLogsEnvelope | ||
from .dynamodb import DynamoDBStreamEnvelope | ||
from .event_bridge import EventBridgeEnvelope | ||
from .sns import SnsEnvelope | ||
from .sqs import SqsEnvelope | ||
|
||
__all__ = ["DynamoDBStreamEnvelope", "EventBridgeEnvelope", "SnsEnvelope", "SqsEnvelope", "BaseEnvelope"] | ||
__all__ = [ | ||
"CloudWatchLogsEnvelope", | ||
"DynamoDBStreamEnvelope", | ||
"EventBridgeEnvelope", | ||
"SnsEnvelope", | ||
"SqsEnvelope", | ||
"BaseEnvelope", | ||
] |
42 changes: 42 additions & 0 deletions
42
aws_lambda_powertools/utilities/parser/envelopes/cloudwatch.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import logging | ||
from typing import Any, Dict, List, Optional, Union | ||
|
||
from ..models import CloudWatchLogsModel | ||
from ..types import Model | ||
from .base import BaseEnvelope | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
class CloudWatchLogsEnvelope(BaseEnvelope): | ||
"""CloudWatch Envelope to extract a List of log records. | ||
The record's body parameter is a string (after being base64 decoded and gzipped), | ||
though it can also be a JSON encoded string. | ||
Regardless of its type it'll be parsed into a BaseModel object. | ||
Note: The record will be parsed the same way so if model is str | ||
""" | ||
|
||
def parse(self, data: Optional[Union[Dict[str, Any], Any]], model: Model) -> List[Optional[Model]]: | ||
"""Parses records found with model provided | ||
Parameters | ||
---------- | ||
data : Dict | ||
Lambda event to be parsed | ||
model : Model | ||
Data model provided to parse after extracting data using envelope | ||
Returns | ||
------- | ||
List | ||
List of records parsed with model provided | ||
""" | ||
logger.debug(f"Parsing incoming data with SNS model {CloudWatchLogsModel}") | ||
parsed_envelope = CloudWatchLogsModel.parse_obj(data) | ||
logger.debug(f"Parsing CloudWatch records in `body` with {model}") | ||
output = [] | ||
for record in parsed_envelope.awslogs.decoded_data.logEvents: | ||
output.append(self._parse(data=record.message, model=model)) | ||
return output |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
from typing import Dict | ||
|
||
from pydantic import BaseModel | ||
|
||
|
||
class AlbRequestContextData(BaseModel): | ||
targetGroupArn: str | ||
|
||
|
||
class AlbRequestContext(BaseModel): | ||
elb: AlbRequestContextData | ||
|
||
|
||
class AlbModel(BaseModel): | ||
httpMethod: str | ||
path: str | ||
body: str | ||
isBase64Encoded: bool | ||
headers: Dict[str, str] | ||
queryStringParameters: Dict[str, str] | ||
requestContext: AlbRequestContext |
44 changes: 44 additions & 0 deletions
44
aws_lambda_powertools/utilities/parser/models/cloudwatch.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import base64 | ||
import json | ||
import logging | ||
import zlib | ||
from datetime import datetime | ||
from typing import List | ||
|
||
from pydantic import BaseModel, Field, validator | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
class CloudWatchLogsLogEvent(BaseModel): | ||
id: str # noqa AA03 VNE003 | ||
timestamp: datetime | ||
message: str | ||
|
||
|
||
class CloudWatchLogsDecode(BaseModel): | ||
messageType: str | ||
owner: str | ||
logGroup: str | ||
logStream: str | ||
subscriptionFilters: List[str] | ||
logEvents: List[CloudWatchLogsLogEvent] | ||
|
||
|
||
class CloudWatchLogsData(BaseModel): | ||
decoded_data: CloudWatchLogsDecode = Field(None, alias="data") | ||
|
||
@validator("decoded_data", pre=True) | ||
def prepare_data(cls, value): | ||
try: | ||
logger.debug("Decoding base64 cloudwatch log data before parsing") | ||
payload = base64.b64decode(value) | ||
logger.debug("Decompressing cloudwatch log data before parsing") | ||
uncompressed = zlib.decompress(payload, zlib.MAX_WBITS | 32) | ||
return json.loads(uncompressed.decode("utf-8")) | ||
except Exception: | ||
raise ValueError("unable to decompress data") | ||
|
||
|
||
class CloudWatchLogsModel(BaseModel): | ||
awslogs: CloudWatchLogsData |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
127 changes: 127 additions & 0 deletions
127
docs/src/gatsby-theme-apollo-docs/components/multi-code-block.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
import PropTypes from 'prop-types'; | ||
import React, {createContext, useContext, useMemo} from 'react'; | ||
import styled from '@emotion/styled'; | ||
import {trackCustomEvent} from 'gatsby-plugin-google-analytics'; | ||
|
||
export const GA_EVENT_CATEGORY_CODE_BLOCK = 'Code Block'; | ||
export const MultiCodeBlockContext = createContext({}); | ||
export const SelectedLanguageContext = createContext(); | ||
|
||
const Container = styled.div({ | ||
position: 'relative' | ||
}); | ||
|
||
const langLabels = { | ||
js: 'JavaScript', | ||
ts: 'TypeScript', | ||
'hooks-js': 'Hooks (JS)', | ||
'hooks-ts': 'Hooks (TS)' | ||
}; | ||
|
||
function getUnifiedLang(language) { | ||
switch (language) { | ||
case 'js': | ||
case 'jsx': | ||
case 'javascript': | ||
return 'js'; | ||
case 'ts': | ||
case 'tsx': | ||
case 'typescript': | ||
return 'ts'; | ||
default: | ||
return language; | ||
} | ||
} | ||
|
||
function getLang(child) { | ||
return getUnifiedLang(child.props['data-language']); | ||
} | ||
|
||
export function MultiCodeBlock(props) { | ||
const {codeBlocks, titles} = useMemo(() => { | ||
const defaultState = { | ||
codeBlocks: {}, | ||
titles: {} | ||
}; | ||
|
||
if (!Array.isArray(props.children)) { | ||
return defaultState; | ||
} | ||
|
||
return props.children.reduce((acc, child, index, array) => { | ||
const lang = getLang(child); | ||
if (lang) { | ||
return { | ||
...acc, | ||
codeBlocks: { | ||
...acc.codeBlocks, | ||
[lang]: child | ||
} | ||
}; | ||
} | ||
|
||
if (child.props.className === 'gatsby-code-title') { | ||
const nextNode = array[index + 1]; | ||
const title = child.props.children; | ||
const lang = getLang(nextNode); | ||
if (nextNode && title && lang) { | ||
return { | ||
...acc, | ||
titles: { | ||
...acc.titles, | ||
[lang]: title | ||
} | ||
}; | ||
} | ||
} | ||
|
||
return acc; | ||
}, defaultState); | ||
}, [props.children]); | ||
|
||
const languages = useMemo(() => Object.keys(codeBlocks), [codeBlocks]); | ||
const [selectedLanguage, setSelectedLanguage] = useContext( | ||
SelectedLanguageContext | ||
); | ||
|
||
if (!languages.length) { | ||
return props.children; | ||
} | ||
|
||
function handleLanguageChange(language) { | ||
setSelectedLanguage(language); | ||
trackCustomEvent({ | ||
category: GA_EVENT_CATEGORY_CODE_BLOCK, | ||
action: 'Change language', | ||
label: language | ||
}); | ||
} | ||
|
||
const defaultLanguage = languages[0]; | ||
const renderedLanguage = | ||
selectedLanguage in codeBlocks ? selectedLanguage : defaultLanguage; | ||
|
||
return ( | ||
<Container> | ||
<MultiCodeBlockContext.Provider | ||
value={{ | ||
selectedLanguage: renderedLanguage, | ||
languages: languages.map(lang => ({ | ||
lang, | ||
label: | ||
// try to find a label or capitalize the provided lang | ||
langLabels[lang] || lang.charAt(0).toUpperCase() + lang.slice(1) | ||
})), | ||
onLanguageChange: handleLanguageChange | ||
}} | ||
> | ||
<div className="gatsby-code-title">{titles[renderedLanguage]}</div> | ||
{codeBlocks[renderedLanguage]} | ||
</MultiCodeBlockContext.Provider> | ||
</Container> | ||
); | ||
} | ||
|
||
MultiCodeBlock.propTypes = { | ||
children: PropTypes.node.isRequired | ||
}; |
Oops, something went wrong.