google-cloud-logging 0.1.0.0 → 1.1.0.0
raw patch · 6 files changed
+279/−40 lines, 6 filesdep +bytestringdep +tastydep +tasty-hunitdep ~google-cloud-commonsetup-changedPVP ok
version bump matches the API change (PVP)
Dependencies added: bytestring, tasty, tasty-hunit
Dependency ranges changed: google-cloud-common
API changes (from Hackage documentation)
- Google.Cloud.Logging.Logs: [$sel:logNames:ListLogsResp] :: ListLogsResp -> [String]
- Google.Cloud.Logging.Logs: [$sel:nextPageToken:ListLogsResp] :: ListLogsResp -> Maybe String
- Google.Cloud.Logging.Logs: instance GHC.Generics.Generic Google.Cloud.Logging.Logs.ListLogsResp
- Google.Cloud.Logging.Logs: instance GHC.Show.Show Google.Cloud.Logging.Logs.ListLogsOps
- Google.Cloud.Logging.Logs: instance GHC.Show.Show Google.Cloud.Logging.Logs.ListLogsResp
- Google.Cloud.Logging.Logs: instance GHC.Show.Show Google.Cloud.Logging.Logs.Resource
+ Google.Cloud.Logging.Logs: ListLogsOps :: Maybe [String] -> Maybe Integer -> Maybe String -> ListLogsOps
+ Google.Cloud.Logging.Logs: [logNames] :: ListLogsResp -> [String]
+ Google.Cloud.Logging.Logs: [nextPageToken] :: ListLogsResp -> Maybe String
+ Google.Cloud.Logging.Logs: [pageSize] :: ListLogsOps -> Maybe Integer
+ Google.Cloud.Logging.Logs: [pageToken] :: ListLogsOps -> Maybe String
+ Google.Cloud.Logging.Logs: [resourceNames] :: ListLogsOps -> Maybe [String]
+ Google.Cloud.Logging.Logs: data ListLogsOps
+ Google.Cloud.Logging.Logs: defaultListLogsOps :: ListLogsOps
+ Google.Cloud.Logging.Logs: getSettings :: Resource -> IO (Either String Settings)
+ Google.Cloud.Logging.Logs: googleLoggingUrl :: String
+ Google.Cloud.Logging.Logs: instance Data.Aeson.Types.FromJSON.FromJSON Google.Cloud.Logging.Logs.DefaultSinkConfig
+ Google.Cloud.Logging.Logs: instance Data.Aeson.Types.FromJSON.FromJSON Google.Cloud.Logging.Logs.Settings
+ Google.Cloud.Logging.Logs: instance GHC.Classes.Eq Google.Cloud.Logging.Logs.DefaultSinkConfig
+ Google.Cloud.Logging.Logs: instance GHC.Classes.Eq Google.Cloud.Logging.Logs.Settings
+ Google.Cloud.Logging.Logs: instance GHC.Internal.Show.Show Google.Cloud.Logging.Logs.DefaultSinkConfig
+ Google.Cloud.Logging.Logs: instance GHC.Internal.Show.Show Google.Cloud.Logging.Logs.ListLogsOps
+ Google.Cloud.Logging.Logs: instance GHC.Internal.Show.Show Google.Cloud.Logging.Logs.ListLogsResp
+ Google.Cloud.Logging.Logs: instance GHC.Internal.Show.Show Google.Cloud.Logging.Logs.Resource
+ Google.Cloud.Logging.Logs: instance GHC.Internal.Show.Show Google.Cloud.Logging.Logs.Settings
- Google.Cloud.Logging.Logs: listLogs :: Resource -> Maybe ListLogsOps -> IO (Either String ListLogsResp)
+ Google.Cloud.Logging.Logs: listLogs :: Resource -> ListLogsOps -> IO (Either String ListLogsResp)
Files
- CHANGELOG.md +4/−0
- README.md +49/−0
- Setup.hs +1/−0
- google-cloud-logging.cabal +8/−4
- src/Google/Cloud/Logging/Logs.hs +174/−35
- test/Spec.hs +43/−1
CHANGELOG.md view
@@ -8,4 +8,8 @@ ## Unreleased +## 1.1.0.0 - 2025-09-11++- Synchronized version bump for v1.1.0.0 release.+ ## 0.1.0.0 - YYYY-MM-DD
README.md view
@@ -3,3 +3,52 @@ Haskell idiomatic client for [Google Cloud Platform](https://cloud.google.com/) Logging service. Full docs are available at https://github.com/tusharad/google-cloud-haskell++## Installation++- Cabal: add to your `.cabal`+ - `build-depends: google-cloud-logging == 1.1.0.0`+- Stack: add to your `package.yaml`+ - `dependencies: - google-cloud-logging == 1.1.0.0`++This package depends on `google-cloud-common` for auth and HTTP helpers.++## Authentication++Authentication is handled by `google-cloud-common` and follows this order:++1. Use `GOOGLE_APPLICATION_CREDENTIALS` to load a Service Account JSON and+ exchange a signed JWT for an access token.+2. Otherwise, use the Compute metadata server (suitable for GCE/GKE).++## Examples++Minimal examples using `Google.Cloud.Logging.Logs`:++```haskell+{-# LANGUAGE OverloadedStrings #-}++import Google.Cloud.Logging.Logs++-- List log names under a project+listLogsExample :: IO ()+listLogsExample = do+ let resource = Projects "my-gcp-project"+ eResp <- listLogs resource defaultListLogsOps+ case eResp of+ Left err -> putStrLn ("Error: " <> err)+ Right res -> print (logNames res)++-- Fetch logging settings for a project+getSettingsExample :: IO ()+getSettingsExample = do+ let resource = Projects "my-gcp-project"+ eRes <- getSettings resource+ case eRes of+ Left err -> putStrLn ("Settings error: " <> err)+ Right settings -> print settings+```++## License++MIT © Contributors
Setup.hs view
@@ -1,2 +1,3 @@ import Distribution.Simple+ main = defaultMain
google-cloud-logging.cabal view
@@ -1,11 +1,11 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.37.0.+-- This file has been generated from package.yaml by hpack version 0.38.1. -- -- see: https://github.com/sol/hpack name: google-cloud-logging-version: 0.1.0.0+version: 1.1.0.0 synopsis: GCP Client for Haskell description: GCP Logging client for Haskell category: Web@@ -36,7 +36,8 @@ build-depends: aeson <3 , base >=4.7 && <5- , google-cloud-common+ , bytestring >=0.9.1.4+ , google-cloud-common >=1.1.0.0 && <1.2.0.0 default-language: Haskell2010 test-suite google-cloud-logging-test@@ -50,6 +51,9 @@ build-depends: aeson <3 , base >=4.7 && <5- , google-cloud-common+ , bytestring >=0.9.1.4+ , google-cloud-common >=1.1.0.0 && <1.2.0.0 , google-cloud-logging+ , tasty >=1.4+ , tasty-hunit >=0.10 default-language: Haskell2010
src/Google/Cloud/Logging/Logs.hs view
@@ -1,46 +1,82 @@-{-# LANGUAGE DeriveAnyClass #-}-{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE TupleSections #-} --- | A client module for interacting with Google Cloud Logging's log management API.------ This module implements the v2 REST API for listing logs from GCP resources.--- For API details, see: <https://cloud.google.com/logging/docs/reference/v2/rest/v2/logs/list GCP Logging API Documentation>+{- |+Module : Google.Cloud.Logging.Logs+License : MIT+Maintainer : maintainers@google-cloud-haskell+Stability : experimental +A client module for interacting with Google Cloud Logging's log management API.+This module implements parts of the v2 REST API for listing logs and fetching+settings.++For API details, see:+<https://cloud.google.com/logging/docs/reference/v2/rest/v2/logs/list GCP Logging API Documentation>+-} module Google.Cloud.Logging.Logs ( listLogs , Resource (..) , ListLogsResp (..)+ , googleLoggingUrl+ , defaultListLogsOps+ , ListLogsOps (..)+ , getSettings ) where import Data.Aeson-import GHC.Generics+import qualified Data.ByteString.Char8 as BS+import Data.Maybe import Google.Cloud.Common.Core --- | Represents GCP resources that can contain logs.--- Constructors take the resource identifier as a String.+{- | Logging url for GCP Logging service+url = "https://logging.googleapis.com/v2"+-}+googleLoggingUrl :: String+googleLoggingUrl = "https://logging.googleapis.com/v2"++{- | Represents GCP resources that can contain logs.+Constructors take the resource identifier as a String.+-} data Resource- = Projects String -- ^ A GCP Project resource with the given project ID- | Organizations String -- ^ A GCP Organization resource with the given organization ID- | BillingAccount String -- ^ A GCP Billing Account resource with the given billing account ID- | Folders String -- ^ A GCP Folder resource with the given folder ID+ = -- | A GCP Project resource with the given project ID+ Projects String+ | -- | A GCP Organization resource with the given organization ID+ Organizations String+ | -- | A GCP Billing Account resource with the given billing account ID+ BillingAccount String+ | -- | A GCP Folder resource with the given folder ID+ Folders String deriving (Eq, Show) -- | Options for customizing the 'listLogs' request data ListLogsOps = ListLogsOps- { resourceNames :: [String] -- ^ List of parent resource names to search (corresponds to 'resourceNames' query parameter)- , pageSize :: Maybe Integer -- ^ Maximum number of results to return (server may return fewer)- , pageToken :: Maybe String -- ^ Pagination token from previous 'ListLogsResp'+ { resourceNames :: Maybe [String]+ -- ^ List of parent resource names to search (corresponds to 'resourceNames' query parameter)+ , pageSize :: Maybe Integer+ -- ^ Maximum number of results to return (server may return fewer)+ , pageToken :: Maybe String+ -- ^ Pagination token from previous 'ListLogsResp' } deriving (Eq, Show) -- | Response from the Cloud Logging API containing log resources data ListLogsResp = ListLogsResp- { logNames :: [String] -- ^ List of log resource names matching the request- , nextPageToken :: Maybe String -- ^ Pagination token for next batch of results (if any)+ { logNames :: [String]+ -- ^ List of log resource names matching the request+ , nextPageToken :: Maybe String+ -- ^ Pagination token for next batch of results (if any) }- deriving (Eq, Show, Generic, FromJSON)+ deriving (Eq, Show) +instance FromJSON ListLogsResp where+ parseJSON = withObject "ListLogsResp" $ \v ->+ ListLogsResp+ <$> v .: "logNames"+ <*> v .:? "nextPageToken"+ -- | Internal helper to convert a Resource to a URL path component toResource :: Resource -> [String] toResource resource =@@ -50,28 +86,131 @@ BillingAccount str -> ["billingAccounts", str] Folders str -> ["folders", str] --- | List log resource names from a GCP resource------ Example:------ > listLogs (Projects "my-project") Nothing------ This makes a request to @v2/projects/my-project/logs@------ Returns 'Either' with error message or 'ListLogsResp' containing:--- * Matching log resource names--- * Pagination token for subsequent requests-listLogs :: Resource -- ^ Parent GCP resource to list logs from- -> Maybe ListLogsOps -- ^ Optional parameters for pagination and filtering- -> IO (Either String ListLogsResp)-listLogs resource _ =+{- | List log resource names from a GCP resource++Example:++> listLogs (Projects "my-project") Nothing++This makes a request to @v2/projects/my-project/logs@++Returns 'Either' with error message or 'ListLogsResp' containing:+* Matching log resource names+* Pagination token for subsequent requests+-}+listLogs ::+ -- | Parent GCP resource to list logs from+ Resource ->+ -- | parameters for pagination and filtering and other resource names+ ListLogsOps ->+ IO (Either String ListLogsResp)+listLogs resource ListLogsOps {..} = do+ let qParams =+ concat+ [ maybeToList $ fmap (("pageSize",) . Just . BS.pack . show) pageSize+ , maybeToList $ fmap (("pageToken",) . Just . BS.pack) pageToken+ , maybe [] (map (("resourceNames",) . Just . BS.pack)) resourceNames+ ] doRequestJSON RequestOptions { reqMethod = GET , reqUrl = googleLoggingUrl- , mbQueryParams = Nothing+ , mbQueryParams = Just qParams , mbReqBody = Nothing , mbReqHeaders = Nothing , mbReqPath = Just $ toPath $ toResource resource <> ["logs"]+ }++{- | Helper function to pass ListLogsOps+| Example+> listLogs (Projects "my-project") (defaultListLogsOps { resourceNames = Just ["projects/my-project-id"] })+-}+defaultListLogsOps :: ListLogsOps+defaultListLogsOps =+ ListLogsOps+ { resourceNames = Nothing+ , pageSize = Nothing+ , pageToken = Nothing+ }++-- | https://cloud.google.com/logging/docs/reference/v2/rest/v2/Settings++-- | Represents the configuration of the default log sink in Google Cloud Logging settings.+data DefaultSinkConfig = DefaultSinkConfig+ { destination :: Maybe String+ -- ^ The export destination for the default sink (e.g., a Cloud Storage bucket).+ , filter :: Maybe String+ -- ^ The filter that determines which log entries are exported.+ , outputVersionFormat :: Maybe String+ -- ^ The format of the log entry output (e.g., 'V2').+ }+ deriving (Show, Eq)++instance FromJSON DefaultSinkConfig where+ parseJSON = withObject "DefaultSinkConfig" $ \v ->+ DefaultSinkConfig+ <$> v .:? "destination"+ <*> v .:? "filter"+ <*> v .:? "outputVersionFormat"++-- | Represents the settings resource in Google Cloud Logging.+data Settings = Settings+ { name :: String+ -- ^ The resource name of the settings.+ , kmsKeyName :: Maybe String+ -- ^ The name of the Cloud KMS key used for log encryption.+ , kmsServiceAccountId :: Maybe String+ -- ^ The service account ID used for accessing the KMS key.+ , storageLocation :: Maybe String+ -- ^ The storage location for log data.+ , disableDefaultSink :: Maybe Bool+ -- ^ Indicates whether the default sink is disabled.+ , defaultSinkConfig :: Maybe DefaultSinkConfig+ -- ^ Configuration details of the default sink.+ , loggingServiceAccountId :: Maybe String+ -- ^ The service account ID used by the logging service.+ }+ deriving (Show, Eq)++instance FromJSON Settings where+ parseJSON = withObject "Settings" $ \v ->+ Settings+ <$> v .: "name"+ <*> v .:? "kmsKeyName"+ <*> v .:? "kmsServiceAccountId"+ <*> v .:? "storageLocation"+ <*> v .:? "disableDefaultSink"+ <*> v .:? "defaultSinkConfig"+ <*> v .:? "loggingServiceAccountId"++{- | Fetches the logging settings for a specified resource.++This function sends a GET request to the Google Cloud Logging API to retrieve the+settings associated with the provided resource.++@+eResult <- getSettings myResource+case eResult of+ Left err -> putStrLn $ "Error: " ++ err+ Right settings -> print settings+@++@since 0.1.0+-}+getSettings ::+ -- | The resource for which to retrieve logging settings.+ Resource ->+ -- | Either an error message or the retrieved settings.+ IO (Either String Settings)+getSettings resource =+ doRequestJSON+ RequestOptions+ { reqMethod = GET+ , reqUrl = googleLoggingUrl+ , mbQueryParams = Nothing+ , mbReqBody = Nothing+ , mbReqHeaders = Nothing+ , mbReqPath =+ Just $ toPath $ toResource resource <> ["settings"] }
test/Spec.hs view
@@ -1,2 +1,44 @@+{-# LANGUAGE OverloadedStrings #-}++module Main (main) where++import Data.Aeson (eitherDecode)+import qualified Data.ByteString.Lazy.Char8 as BSL+import Test.Tasty (TestTree, defaultMain, testGroup)+import Test.Tasty.HUnit (assertBool, assertEqual, testCase)++import Google.Cloud.Logging.Logs+ ( ListLogsOps (..)+ , ListLogsResp (..)+ , Resource (..)+ , defaultListLogsOps+ , googleLoggingUrl+ )+ main :: IO ()-main = putStrLn "Test suite not yet implemented"+main = defaultMain tests++tests :: TestTree+tests =+ testGroup+ "google-cloud-logging"+ [ testCase "googleLoggingUrl is v2 endpoint" $ do+ assertEqual "Endpoint" "https://logging.googleapis.com/v2" googleLoggingUrl+ , testCase "defaultListLogsOps has all fields Nothing" $ do+ let d = defaultListLogsOps+ assertEqual "resourceNames" Nothing (resourceNames d)+ assertEqual "pageSize" Nothing (pageSize d)+ assertEqual "pageToken" Nothing (pageToken d)+ , testCase "Decode ListLogsResp with nextPageToken" $ do+ let json =+ BSL.pack+ "{\n \"logNames\": [\"projects/p/logs/a\", \"projects/p/logs/b\"],\n \"nextPageToken\": \"tok\"\n}"+ case eitherDecode json of+ Left err -> assertBool ("Failed to decode: " <> err) False+ Right (ListLogsResp names tok) -> do+ assertEqual "names" ["projects/p/logs/a", "projects/p/logs/b"] names+ assertEqual "token" (Just "tok") tok+ , testCase "Resource Show/Eq constructors" $ do+ assertEqual "Projects" (Projects "p") (Projects "p")+ assertEqual "Show Organizations" "Organizations \"o\"" (show (Organizations "o"))+ ]